From d577a0e18b6e9e0ae50f1f2d131c82107dcc6e2b Mon Sep 17 00:00:00 2001 From: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:10:37 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=96=89=EB=8F=99=EB=8C=80=EC=9E=A5=20?= =?UTF-8?q?v1.0.0=20(#486)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: DB 데이터를 drop 할 수 없도록 DB user 권한 수정합니다. (#485) * chore: webpack, react, typescript 환경 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 * chore: eslint, prettier 설정 Co-authored-by: JinHo Kim Co-authored-by: Pakxe * docs: pr 템플릿 및 issue 템플릿 세팅 Co-authored-by: pakxe , soi-ha , jinhokim98 * docs: issue 템플릿에 타이틀과 관련된 부가 정보 추가 Co-authored-by: pakxe , soi-ha , jinhokim98 * chore: 모든 install 에 legacy-peer-deps를 사용하도록 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: emotion css props 사용 예제 작성 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: webpack, @emotion/react 라이브러리 설치 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: css props를 사용하기 위해 'jsxImportSource' 옵션 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: css props 사용 위해 모든 파일 최상단에 주석을 자동으로 작성해주도록 플러그인 세팅 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: 개발서버 포트번호 3001 -> 3000 으로 수정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: prettier에서 useTabs를 사용하지 않도록 제거 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: 여러 명이 co-authored-by로 들어갈 수 있는지 테스트 커밋 Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari * chore: 임시로 지웠던 types 옵션을 다시 활성화 Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari * chore: 기본 webpack 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: theme, token 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: storybook 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Button 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Text 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * fix: webpack 설정 entry 파일 확장자 tsx에서 ts로 변경 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: modify-source-webpack-plugin 의존성 반영되지 않은 것 추가 Co-authored-by: pakxe * chore: css파일을 처리하기 위한 webpack 세팅 Co-authored-by: pakxe * design: 기본 css style 초기화 작업 Co-authored-by: pakxe * feat: 메인 페이지 퍼블리싱 Co-authored-by: pakxe * feat: 이벤트 생성 페이지 퍼블리싱 Co-authored-by: pakxe * feat: 이벤트 생성 완료 페이지 퍼블리싱 Co-authored-by: pakxe * design: 전역 스타일링 설정 Co-authored-by: pakxe * feat: 라우터 셋팅 Co-authored-by: pakxe * feat: 앱의 진입점 설정 Co-authored-by: pakxe * feat: 라우트 경로 설정 Co-authored-by: pakxe * fix: 라우트 이동 시 페이지가 제대로 보이지 않던 문제 해결 Co-authored-by: pakxe * feat: 모달 컴포넌트 생성 Co-authored-by: pakxe * feat: 스위치 컴포넌트 생성 Co-authored-by: pakxe * feat: 초기인원 세팅 기능 퍼블리싱 및 구현 Co-authored-by: pakxe * feat: 행동 추가를 위한 모달 컨텐츠 구현 Co-authored-by: pakxe * feat: 지출 내역 관리 기능구현 Co-authored-by: pakxe * feat: 인원 관리 기능구현 Co-authored-by: pakxe * feat: 행사관리 페이지 퍼블리싱 및 구현 Co-authored-by: pakxe * feat: 해커톤 로그 출력을 위한 임시처리 Co-authored-by: pakxe * feat: 프로젝트 초기 설정 * feat: 엔티티 추가 * refactor: gitignore 수정 * refactor: 엔티티 컬럼명 변경 * chore: path alias 설정 및 lint 마이그레이션 * [FE] 해커톤 범위 디자인시스템 구현 (#36) * feat: FixedButton Component 구현 Co-authored-by: soi-ha * feat: Input component 구현 Co-authored-by: soi-ha * feat: Title component 구현 Co-authored-by: soi-ha * feat: BottomSheet component 구현 Co-authored-by: soi-ha * fix: BottomSheet component 빌드 오류 해결 * move: 전체적인 파일 경로 수정정 * move: 전체적인 파일 경로 수정 * fix: npm build를 위한 설정 변경 * feat: IconButton Component 추가 * design: IconButton height가 제대로 적용되지 않는 오류 수정 * feat: npm 배포를 위한 환경설정 및 파일 경로 수정 Co-authored-by: Soyeon Choe * style: eslint 적용 * design: globalStyle root BG 변경 * design: globalStyle background 변경 * fix: Title type 변경 * chore: storybook svg 사용을 위한 main.ts 설정 * feat: BillItem component 구현 * feat: InOutItem Component 구현 * feat: StepItemComponent 구현 * chore: storybook preview background color 수정 * chore: tsconfig.json sourcemap 속성 변경 * chore: npm v0.1.0 배포 --------- Co-authored-by: soi-ha Co-authored-by: Soyeon Choe * feat: CI/CD 파이프라인 구축 (#42) * feat: ci/cd 구축 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * feat: cicd 테스트 객체 제거 * feat: cicd 테스트 객체 제거 * feat: 행사 생성 기능 구현 * feat: 지출 내역 추가 기능 구현 * refactor: event의 마지막 action 순서 조회 로직 수정 * refactor: BillAction fetch type 수정 * test: 불필요한 mocking 제거 * refactor: 중요도에 따라 필드 순서 변경 * fix: BillAction 저장 Dto 검증 추가 * [FE] 디자인 시스템 수정 (#46) * chore: storybook 관련 dependency 설치 * fix: Text component 수정 * feat: TextButton Component 구현 * fix: Title Component 수정 * feat: input component background color InputType 추가 및 입력제거 아이콘 변경 * feat: Switch component 구현 * feat: TopNav component 구현 * feat: Tab 컴포넌트 구현 * refactor: Tab type type.ts로 분리 * feature: ExpenseList component 구현 * design: 폰트 size, weight, color 수정 * feat: BillItem에 드래그핸들러 포함 여부를 props로 받을 수 있도록 구현 * design: 드래그핸들러 여부에 따라 패딩을 다르게 하도록 수정 * feat: Flex 컴포넌트 구현 * feat: 잡고 이동할 수 있는 DragHandleItem 컴포넌트 모습 구현 아직 잡고 이동하는 기능은 없습니다. * chore: DragHandleItem 컴포넌트의 스토리북 작성 * feat: BillItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * feat: InOutItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * fix: 스토리북에서 배열 형태로 모습 테스트를 할 수 있도록 type 수정 * feat: InOutItem에서 드래그 여부를 할 수 있도록 type 추가 * feat: StepItem 컴포넌트가 Flex 컴포넌트를 사용하도록 대체 * feat: children을 포함하는 타입을 빠르게 선언하기 위한 타입 구현 * feat: 카멜 케이스를 케밥 케이스의 문자열로 반환하는 함수 구현 * design: 사용하지 않게된 css 객체 제거 * feat: COLORS 자동완성을 위한 타입 추가 --------- Co-authored-by: 김진호 Co-authored-by: Soyeon Choe Co-authored-by: pakxe * refactor: BillAction 검증 로직 수정 * refactor: 지출 내역 추가 로직 수정 * feat: BillAction과 Action cascade 옵션과 orphanRemoval 옵션 변경 * test: event save 로직 분리 * test: DisplayName 변경 Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * test: 경계값 테스트로 변경 Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * test: 지출 내역 생성 테스트 수정 * feat: PR 후 테스트 리포트 발행 기능 추가 (#56) * test: 미사용 test class 제거 * [BE] 인원 변동 기능 구현 (#47) * feat: 인원 변동 기능 구현 Co-authored-by: kunsanglee * refactor: 메서드 분리 Co-authored-by: kunsanglee * refactor: 코드 컨벤션 Co-authored-by: kunsanglee * refactor: 멤버 액션 생성 클래스 분리 Co-authored-by: kunsanglee * refactor: MemberActionFactory 코드 리팩터링 * refactor: DTO 클래스명 리팩터링 * refactor: MemberActionRepository Lazy Loading 적용 * test: MemberActionFactory createMemberActions 결과 검증 테스트 추가 * refactor: 컨벤션에 맞게 수정 Co-authored-by: kunsanglee * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 Co-authored-by: kunsanglee Co-authored-by: Arachne * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 * refactor: 컨벤션에 맞게 수정 * feat: 사용자 이름이 중복 입력되는 예외 상황 검증 Co-authored-by: kunsanglee Co-authored-by: Arachne * refactor: 메서드 순서 변경 Co-authored-by: Arachne --------- Co-authored-by: kunsanglee Co-authored-by: Arachne authored-by: khabh * [BE] 패키지 구조 변경 (#62) * chore: 패키지 구조 변경 * test: 패키지 구조 변경 --------- Co-authored-by: Arachneee * feat: api wrapping 객체 생성 (#68) Co-authored-by: JinHo Kim Co-authored-by: Pakxe Co-authored-by: Soyeon Choe * [FE] @svgr/webpack 플러그인 설치 * feat: 행사 정보 조회 기능 구현 (#75) Co-authored-by: kunsanglee * [BE] 설정 파일 서브 모듈 생성 (#82) * feat: 설정 파일을 서브모듈로 관리 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: 테스트 설정 파일 추가 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: 도커 파일 내 profile 설정 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: gitflow에 서브 모듈 설정 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh --------- Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * [BE] 요청 데이터가 맵핑되지 않는 문제 해결 (#86) Co-authored-by: kunsanglee Co-authored-by: Arachneee Co-authored-by: khabh * feat: 현재 참여 인원 조회 기능 구현 (#70) * design: 탭 컴포넌트 height 소수점 문제 (#51) * design: tab height 소수점 문제 해결 * fix: tab component after 가상태그를 활용해서 div 태그 제거 * chore: 배포, CI 및 테스트 전략 수립 #32 * chore: frontend-push yaml 파일 추가 * chore: eslint-import-resolver-typescript 추가 * chore: eslint explicit-module-boundary-types 옵션 해제 * chore: noUnused tsconfig.json 설정 제거 * chore: eslint no-use-before-define 옵션 제거 * style: eslint 적용 * fix: workflow yml 파일 수정 * feat: 행사 생성 페이지 구현 (#87) * feat: 행사 생성 페이지 디자인시스템 적용 * design : index.css 수정 * feat: 행사 생성 api 연결 * style: lint 적용 * feat: 행사 홈 페이지 구현 (#88) * chore: env와 디자인 시스템 라이브러리 설치 * chore: 현재 불필요한 옵션 비활성화 * chore: env를 사용하기 위한 환경 세팅 * feat: 디자인 시스템 provider 사용 * design: index.css 정한대로 수정 * feat: apiBaseUrl 선언 * feat: router에 Home 페이지 연결 * feat: api호출 시 매번 들어가는 prefix 상수화 * feat: eventId를 타입에 포함시키기 위한 WithEventId 타입 선언 * feat: 지출 내역 추가 api 구현 * feat: 행사 생성 api 구현 * feat: 참여자 목록 갱신 api 구현 * feat: 정산 현황 요청 api 구현 * feat: 행사 이력 조회 api 구현 * feat: 참여자 별 정산 목록 컴포넌트 구현 * feat: 전체 지출 내역 컴포넌트 구현 * feat: router url 논의된 대로 선언 * feat: 정산 현황 검색을 위한 훅 구현 * feat: 스텝 목록을 관리하기 위한 훅 구현 * chore: 정산 현황 목 데이터 작성 * chore: 전체 지출 내역 목 데이터 작성 * feat: 홈 페이지 레이아웃 구현 * feat: 홈 페이지 안에 들어갈 컨텐츠 구현 * feat: Home -> HomePage로 import 할 수 있도록 export 작성 * feat: 스텝 목록에 필요한 타입 선언 * chore: url 경로 포멧 변경에 따른 수정 * chore: package-lock 업로드 * chore: import 개행 추가 * chore: 디자인 시스템 업데이트 * fix: inOutType 대문자로 넘기도록 수정 * feat: TopNav 추가 * chore: 사용하지 않는 util라이브러리 삭제 * chore: dotenv 세팅 수정 * feat: 현재 참여자 검색 component 생성 (#78) * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: search 컴포넌트 구현 * design: input 컴포넌트 마진 추가로 searchTerms 마진 추가 * refactor: 사용하지 않는 onChange 제거 * refactor: setKeyword -> setState로 setter라는 의미 명시 * style: early return 뒤 개행 추가 --------- Co-authored-by: 이태훈 * feat: CORS 설정 (#90) * feat: CORS 설정 * refactor: CORS 설정 분리 * test: yml에 CORS 설정 추가 * feat: Origin 추가 * feat: Cors 설정에 HTTP OPTIONS 메서드 추가 --------- Co-authored-by: juha * feat: 행사 커스텀 예외 처리 (#92) * feat: 행사 커스텀 예외 처리 * feat: 커스텀 예외 적용 * feat: 참여자별 정산 현황 조회 기능 구현 (#77) * feat: api 명세에서 행사 url을 표현하는 용어와 전달 방식 수정 (#98) * feat: 행사 url 명세를 token에서 eventId로 변경 * feat: 행사 url을 헤더가 아닌 바디로 전달 * test: 행사 생성 컨트롤러 테스트 수정 * feat: 행사 생성 응답 dto에 필드명 수정 * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 (#102) * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 * feat: jpa dll-auto none에서 create로 변경 * refactor: 지출 내역 생성 및 현재 참여 인원 조회 예외 메시지 변경 (#100) * refactor: 지출 내역 생성 예외 메시지 변경 * refactor: 현재 인원 조회 예외 메시지 변경 * refactor: 예외 메시지 전달 방법 수정 * refactor: 참여자별 정산 현황 조회 예외 메시지 변경 (#106) * refactor: 행사 생성 API 예외 메세지 및 DTO 검증 애너테이션 추가 (#103) * refactor: 행사 생성 API 예외 메세지 추가 및 DTO 검증 애너테이션 추가 * refactor: 행사 생성 API EventSaveRequest name을 eventName으로 변경 * refactor: 행사 생성 요청 객체 검증 애너테이션 @Size 제거 * refactor: 연속된 공백 검증 및 예외 메세지 상수 사용하도록 리팩터링 * feat: 행사 관리 페이지 구현 (#107) * style: eslint 적용 * chore: typescript with invalid interface loaded as resolver 해결을 위한 eslint-import-resolver-typescript 설치 * chore: SetInitialParticipatns & SetActionModalContent를 Modal의 index.ts에서 export 추가 * design: HDesignProvider 적용 * design: 행사 관리 페이지 퍼블리싱 * design: 초기 인원 설정 Modal 퍼블리싱 * design: 지출내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 Modal 내부 퍼블리싱 * feat: TopNav 추가 및 props 추가 * design: BottomSheet 내부 퍼블리싱 (Input overflow시 scroll) * design: 행사 지출/인원 변동 내역 생성 퍼블리싱 * design: switch와 container의 gap 추가 * design: scroll시 모든 자식 요소가 안 보이는 에러 해결 * design: MainLayout 적용 및 root 태그에 height 적용 * design: 지출 내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 생성 Modal 내부 퍼블리싱 * chore: develop 브랜치 merge로 인한 수정 * chore: 불필요한 import 삭제 * chore: haengdong-design 버전 업데이트 설치 * remove: 사용하지 않는 파일 제거 * chore: TopNav 수정된 디자인 시스템 설치 및 StepList 수정 주석 추가 * style: lint 적용 * feat: Input 값 입력시 다음 Input이 생성되는 hook 기능 구현 * feat: useDynamicInput에 auto focus 및 scrollIntoView 기능 추가 * feat: 초기 인원 설정 및 인원 변동 내역 Modal에 useDynamicInput 적용 * feat: 지출 내역에 대한 기능 구현 (useDynamicInputPairs 훅 생성) * chore: 불필요한 props 제거 및 backlog 주석 추가 * fix: BottomSheet의 onClick을 통해 submit되는 오류 수정 * fix: setParticipants를 분리하여 참여 인원 관리 * fix: setOrder를 분리하여 지출 내역 차수 관리 * chore: 사용하지 않는 상태 제거 * chore: haengdong-design 버전 업데이트 반영 * fix: 작성된 값을 수정할 수 없는 에러 해결 * chore: 에러 발생 수정에 대한 주석 추가 * chore: 디자인시스템 버전 업데이트 반영 * fix: 예외에서 정의한 메세지를 꺼내지 못하는 오류 해결 (#111) * feat: 퍼블리싱된 페이지 매끄럽게 연결 (#114) * chore: 디자인시스템 업데이트 반영 * feat: fixed button 클릭시 router 반영 * feat: 총 지출 금액 추가 및 StepList 연결 * refactor: 인원 변동 요청 형태 변경 (#117) * feat: 액션 이력 조회 기능 구현 (#76) * feat: 액션 이력 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * feat: 액션 이력 조회 반환 형식 변경 * test: 액션 이력 조회 테스트 삭제 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> * chore: frontend yml lint 과정 수정 (#120) * fix: 액션 이력이 없는 경우 빈 리스트 반환 (#122) * fix: 액션 이력 조회 오류 수정 (#124) * fix: HaengdongException 적용 안된 부분 적용 * fix: Transactional 추가 및 StepResponse 로직 수정 * fix: StepResponse 로직 수정 (#126) * test: Gradle, Docker 캐싱을 위한 Feature/#121 test (#128) * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * test * after cache * after cache2 * test: Gardle, Docker 캐싱을 위한 Feature/#121 test2 (#130) * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * after cache * revert: gradle cache, docker cache (#133) * refactor: 애플리케이션 도커 포트 번호 수정 (#134) * refactor: Docker 빌드 성능 개선 (#138) * refactor: 참여자 정산 현황 로직 리펙토링 (#110) * refactor: 참여자 정산 현황 로직 수정 * refactor: forEach -> stream 변경 * chore: storybook chromatic 배포 (#81) * chore: storybook chromatic workfloe * style: EOL 제거 * chore: storybook 배포를 위한 workflow 설정 * chore: storybook 배포를 위한 workflow 설정 * chore: workflow node 설정 추가 * chore: lint flow path 변경 * chore: run lint 수정 * chore: eslint-config-prettier 추가 * chore: lint 적용 * chore: airbnb 제거 * chore: eslint 설정 수정 * chore: chromatic working directory 변경 * feat: 2차 스프린트 API 연결 (#137) * chore: storybook 관련 dependency 설치 * feat: post api에도 response를 받을 수 있도록 수정 * refactor: parameter가 파스칼케이스인 부분을 카멜 케이스로 수정 * feat: 행사명을 가져오는 api 함수 구현 * feat: interface 수정에 따라 body 변경 * feat: 지출 내역을 추가하는 api 연결 * feat: 최초 참여자를 추가하는 api 연결 * feat: 참여자 수를 조정하는 api 연결 * refactor: name -> title로 파라미터명 수정 * feat: 이벤트아이디를 url에서 불러오는 훅 구현 * feat: 지출 내역, 인원 조정 api연결 후 provider로 전파 * feat: url에서 eventId를 받아오도록 추가 * feat: submit이벤트를 form 엘리먼트에 연결 * remove: 사용하지 않는 파일 제거 * feat: useContext를 사용해 총 가격을 불러오도록 연결 * feat: provider를 사용하기 위한 Layout 컴포넌트 추가 * feat: 디자인시스템 수정에 다른 컴포넌트 호출 형태 변경 * chore: 주석 추가 * remove: 사용하지 않는 파일 제거 * feat: router 에 home, admin 경로에서 띄울 컴포넌트 연결 * fix: 변경된 interface에 맞게 body 수정 * feat: 참여자 목록을 넘겨주지 않고, 참여자 타입 전달 * chore: 불필요한 props 삭제 * feat: 공백된 값 제거 * feat: 네비게이션을 위한 구현 * fix: useStepList훅이 context를 반환하도록 수정 * feat: TopNav 추가 * feat: Admin 페이지 구현 * feat: Home 페이지 구현 * chore: 디자인시스템 라이브러리 업데이트 * chore: await 추가 * feat: stepList를 호출하도록 api 연결 * chore: 사용하지 않는 변수 제거 * chore: lint 적용 * feat: steps를 꺼내서 return하도록 수정 * feat: 인원이 있어야 memberNameList를 갱신하도록 로직 작성 * feat: StepList 의 타입 작성 * design: 불필요한 padding 제거 * chore: 관리 탭에서 StepList를 보여주기 위해 임시로 조건문 제거 * feat: 홈 페이지에서 총 지출 금액 표시 * chore: 디자인 시스템 업데이트 * fix: meta tag 설정 - mixed content, scalable 등 * design: 메인 페이지 및 행사 생성 페이지 디자인 수정 * fix: 새로 고침하면 내역이 출력되지 않는 오류 수정 eventId의 변화에 따라 지출 내역을 다시 호출하도록 종속성을 연결하지 않아서 발생한 문제입니다. * chore: Content-Security-Policy 삭제 * fix: FixedButton disabled 속성 추가 * fix: 행사 이름 입력 페이지 FixedButton disalbed 추가 및 공백 제거 * style: lint 적용 * fix: 불필요한 인자를 넘겨주는 것 제거 * chore: 사용되지 않는 import 제거 * fix: 참여자별 지출 내역을 받아오는 api의 엔드포인트 올바르게 수정 * fix: eventId, 전체 검색 결과에 따라 검색 결과가 보여지도록 수정 * design: 이벤트 홈 타이틀과 탭 사이 공백 제거 * feat: 임시로 행사 이름을 표시하도록 수정 * style: 사용하지 않는 변수 및 import 제거 * design: 전역 스크롤바 숨김 처리 * design: 바텀 버튼만큼 contents 위로 올라오도록 변경 * rename: steList 타입 파일 useStepList 폴더로 이동 후 type.ts로 이름 변경 * chore: 디자인시스템 버전 업데이트 * feat: 검색창 placeholder 참여자 이름 추가 --------- Co-authored-by: 이태훈 Co-authored-by: 김진호 Co-authored-by: pakxe * refactor: 도커 계정 관련 정보 secrets으로 수정 (#139) * feat: 2차 스프린트 디자인 시스템 수정 (#83) * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: TopNav none 타입 추가 * chore: storybook-addon-react-router-v6 dev dependency 추가 * fix: ExpenseItem button props 넣을 수 있도록 수정 * design: button cursor pointer 전역설정 * refactor: BottomSheet component 구조 수정 * chore: v0.1.4 배포 * refactor: tab components 합성방식으로 변경 * feat: Flex component backgroundColor 받을 수 있도록 변경 * fix: 주석이 xml 내부에서 적용안되던 오류 해결 * chore: v0.1.5 배포 * refactor: flex background prop 로직 처리 방법 변경 * feat: MainLayout backgroundColor prop 추가 * fix: flex backgroundColor defaultValue 제거 * chore: v0.1.6 배포 * fix: MainLayout margin padding으로 변경 * fix: Switch 및 TopNav 내부 로직 변경 * test: Switch storybook 수정 * fix: TopNav navigate currentPath를 이용하도록 수정 * feat: v0.1.18 배포 * fix: TopNav navigate 변경 * design: tab item과 panel 사이에 gap 넣을 수 있도록 설정 및 flex container 사용 * refactor: in out type uppercase로 수정 * design: in out item font size 변경 및 텍스트 바꿔서 작성한 내용 수정 * test: InOutItem storybook 수정 * chore: v0.1.20 배포 * design: hasDragableItem 비활성화 시 마진 수정 * fix: props 네이밍 스토리북에 반영 * fix: navigate 뒤로가기 3번 발생하는 이슈 해결 * chore: v0.1.22 배포 * fix: Switch 내부의 불필요한 로직 제거 * chore: v0.1.23 배포 * fix: navigate path 로직 변경 * fix: 새로고침 됐을 때 해당 location 페이지를 유지하도록 수정 * style: children이 없는 태그 스스로 닫도록 수정 * style: todo 주석 제거 * chore: v0.1.25 배포 * design: fixedButton position 변경 * chore: v0.1.26 배포 * fix: 라우팅 변경 이동 오류 해결 * chore: v0.1.27 배포 * chore: v0.1.28 배포 * fix: location set 로직을 home 모드에서만 작동하도록 변경 * chore: v0.1.29 배포 * fix: TopNav navigation 로직 외부에서 넣도록 변경 * chore: v0.1.30 배포 * fix: index.ts 경로 문제로 제거 * chore: v0.1.13 배포 * chore: v0.1.32 배포 * fix: Fixed Button 하단 고정되도록 변경 * chore: v0.1.33 배포 * v0.1.35 배포 * fix: 가격과 원을 붙여서 표기 * fix: TopNav가 children이 없어도 작동하도록 변경 * fix: children이 필수가 아니도록 변경 * remove: 사용하지 않는 NavSwitch 제거 * chore: 파이프라인 테스트를 위한 push * chore: 파이프라인 테스트를 위한 push * remove: merge를 위한 /sever dir 삭제 * style: lint 적용 --------- Co-authored-by: 이태훈 Co-authored-by: pakxe * chore: server directory 복구 (#150) * fix: gradlew 권한 버그 수정 (#152) * remove: 클라이언트 코드 삭제 * refactor: CD workflow main, develop 분리 (#163) * refactor: CD workflow main, develop 분리 및 dockerfile 수정 * refactor: trigger test 브랜치 추가 * refactor: feature/#147 에 push test * refactor: github actions self-hosted runner tag 추가 * refactor: feature/#147 runner 구분 테스트 * refactor: feature/#147 prod runner 구분 테스트 * refactor: feature/#147 prod runner 구분 테스트2 * refactor: feature/#147 prod runner 구분 테스트3 * refactor: feature/#147 prod runner 구분 테스트3 * refactor: prod, dev yml 분리 완료 및 서버 테스트 완료 * feat: 로그 모니터링 환경 구축 (#169) * feat: 예외메시지 구체화 (#161) * feat: 예외 핸들링 추가 * refactor: 예외 메시지 구체화 및 검증 역할 변경 * feat: 에러 코드 추가 * style: 개행 제거 * refactor: 멤버 액션 예외 ErrorCode 분리 * feat: 로깅 추가 * refactor: 액션 이력 조회 리펙토링 (#141) * feat: 멤버 액션 삭제 기능 구현 (#181) * feat: 액션 삭제 기능 구현 중 지출 삭제 가능, 인원 삭제는 아직입니다. * feat: 멤버 액션 삭제 구현 Co-authored-by: pakxe Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee * feat: 맴버 액션 삭제 기능 구현 * refactor: api 매개변수에 값 넣도록 수정 * fix: 테스트 코드에 action 올바르게 사용하도록 수정 --------- Co-authored-by: 김진호 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: pakxe * feat: ERD svg 생성하여 스키마 변경에 대한 이력 관리 (#190) * feat: 지출 액션 수정 기능 구현 (#180) * feat: 지출 액션 삭제 기능 구현 (#179) * feat: 행사의 전체 참여자 중 특정 참여자의 멤버 액션을 모두 삭제하는 기능 구현 (#185) * feat: 행사의 전체 참여자 중 특정 참여자의 멤버 액션을 모두 삭제하는 기능 구현 * test: eventId String으로 변경 * fix: 다른 행사에 있는 멤버 액션도 지워지는 버그 수정 * refactor: 전체 참여자 중에서 특정 참여자를 전부 삭제하는 메서드명 변경 * refactor: 전체 참여자 중에서 특정 참여자를 전부 삭제하는 메서드명 변경 * refactor: MemberActionController 메서드 파라미터 컨벤션 반영 * refactor: conflict resolve * refactor: conflict resolve * feat: 행사에 참여한 전체 인원 조회 기능 구현 (#195) * feat: 행사에 참여한 전체 인원 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * refactor: EventServiceTest, MemberActionRepository 코드 리팩터링 * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: workflows runs-on self-hosted로 변경 Co-authored-by: 3juhwan <13selfesteem91@naver.com> --------- Co-authored-by: kunsanglee * feat: 행사 참여 인원 이름 변경 기능 구현 (#197) * feat: 행사 참여 인원 이름 변경 기능 구현 * refactor: 지출 액션 수정 기능 리펙토링 --------- Co-authored-by: Arachneee * refactor: API 엔드포인트 수정 (#200) * refactor: 멤버 액션, 지출 액션 관련 API 엔드포인트 수정 * refactor: 요청 url에 token을 eventId로 수정 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * feat: 테스트 데이터 클리너 구현 (#199) * feat: 테스트 데이터 클리너 구현 * feat: 테스트 클리너 상수, 메서드 분리 * refactor: 데이터베이스 클리너 적용 * feat: 행사 관리자 비밀번호 추가 (#213) * feat: 이벤트 비밀번호 추 * test: 테스트 공통 설정 클래스 분리 * feat: 어드민 인터셉터 추가 및 jwt 설정 추가 * feat: 이벤트 로그인 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh * feat: 쿠키 설정 분리 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh * submodule 업데이트 * style: 주석 제거 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh * refactor: 로컬 환경 쿠키 secure 옵션 제거 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh * test: 접근제어자 수정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh * test: 개행 추가 Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> Co-authored-by: kunsanglee <85242378+kunsanglee@users.noreply.github.com> Co-authored-by: khabh * fix: 쿠키 인증 버그 수정 (#222) Co-authored-by: khabh * fix: 쿠키 인증 버그 수정 (#235) * refactor: 에러 코드 재정의 (#227) * refactor: 에러 코드 재정의 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: 변수를 받는 예외 메세지 수정 Co-authored-by: 3juhwan <13selfesteem91@naver.com> --------- Co-authored-by: kunsanglee Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * fix: 쿠키 저장 오류 2차 수정 (#237) * fix: 쿠키 인증 버그 수정 Co-authored-by: khabh * fix: 쿠키 인증 버그 수정 --------- Co-authored-by: khabh * feat: REST docs를 통한 문서화 (#238) * feat: REST Docs 적용 * feat: REST Docs prettyPrint 및 snippets 적용 * feat: REST Docs에 예외 항목 추가 * test: 행사 액션 이력 조회 테스트 추가 * refactor: 중복된 http-request snippet 제거 * refactor: 사용되지 않는 snippet 제거 * refactor: 빌드 시 자동으로 문서 최신화하도록 gradle 설정 추가 * fix: CookieProperties에 sameSite 옵션 추가 --------- Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * fix: JWT 유효기간 만료 버그 수정 (#248) * fix: JWT 기간 오류 수정 * fix: JWT 기간 오류 수정 * feat: 관리자 권한 확인 API 구현 (#259) * feat: 관리자 권한 확인 API 구현 * backend-pull-request workflow 파일 수정 * feat: HTTP Method를 POST에서 GET으로 변경 * fix: 참여자 삭제 서비스 메서드에 Transactional 추가 (#265) Co-authored-by: 3juhwan <13selfesteem91@naver.com> * refactor: application.yml metrics 추가 (#269) * feat: CI/CD 숙제 (#290) * feat: CI/CD 숙제 (#291) * refactor: 행사 참여 인원 이름 변경 api 수정 (#268) * refactor: 회원 이름 변경 api 여러명으로 추가 * style: 메소드 순서 변경 * fix: rest docs 저장 파일 위치 변경 (#273) * fix: 어드민 권한 확인 불가 버그 수정 (#275) * fix: 행사 로그인 불가 버그 수정 (#283) * fix: CI/CD 트리거 조건에서 server 폴더 조건 제거 (#308) * fix: CI 트리거 조건을 수정 * feat: be-dev CD 트리거 조건에서 server 폴더 제거 * feat: pr 머지시 issue close 기능 추가 (#309) * refactor: yml, Dockerfile TZ Asia/Seoul 적용 (#305) Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> * refactor: actuator health 엔드포인트 설정 변경 (#303) * feat: actuator health 엔드포인트 설정 변경 * refactor: AdminInterceptor log level 변경 --------- Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * feat: 서버 로그 볼륨 마운트 설정 (#300) * feat: 로그 파일 볼륨 설정 * feat: 볼륨 이름 지정 * feat: LogBack 롤링 정책 수정, 로그 레벨에 따른 분리 (#332) * feat: Logback 로그 레벨 분리 * feat: Lockback 로그 레벨 분리 --------- Co-authored-by: Arachneee * fix: 서브 모듈 프로파일 오타 수정 (#334) * refactor: 현재 참여 인원 목록 조회 API 반환 형식 수정 (#361) * feat: BillActionDetail 베이스 코드 생성 (#363) * feat: 액션 이력 조회 v2 기능 구현 (#375) * [BE] 행사 참여 인원 또는 지출 총액 변동시 차등 정산 초기화 기능 구현 (#370) * feat: 지출 액션 수정시 지출 디테일 초기화 기능 구현 * feat: 맴버 액션 삭제시 지출 디테일 초기화 기능 구현 * feat: 맴버 삭제시 지출 디테일 초기화 기능 구현 * fix: 버그 수정 * fix: 버그 수정 * feat: 요구사항 변경에 따른 지출 내역 추가, 지출 액션 삭제 API 수정 (#373) * feat: 지출 내역 추가 시, 상세 내역 생성 로직 추가 * feat: 지출 내역 삭제 시, 상세 내역 삭제 로직 추가 * fix: 멤버가 없는 상황에 대해 0으로 나누는 상황 방지 * refactor: 참여자별 정산 현황 조회 및 액션 이력 조회 수정 (#377) * refactor: BillActionDetail 변경 사항을 반영하여 참여자별 정산 현황 조회하도록 수정 * refactor: 액션 이력 조회 시 지출 액션 고정 금액 설정 여부 필드 추가 * refactor: isFixed 필드 삭제 * refactor: 메서드 이름 변경 * fix: BillAction 변경 로직 수정 * feat: 참여자 개별 지출 금액 수정 및 조회 기능 구현 (#378) * feat: 참여자 개별 지출 금액 수정 기능 구현 * refactor: BillActionDetailService 코드 리팩터링 * docs: restdocs 작성 * feat: 참여자별 지출 금액 조회 기능 구현 * docs: index.adoc에 billActionDetail.adoc 추가 * refactor: 충돌 해결 * feat: 에러를 재현할 수 있는 로그로 수정 (#392) * feat: 로깅에 요청 정보 포함 * feat: 개발 환경 ddl update로 변경 * feat: 예외 처리 및 로깅 형식 수정 (#394) * fix: 리스트 형태의 요청 바디에 null을 넣으면 500이 뜨는 에러 수정 * feat: 로그를 json 형태로 수정 * feat: 예외 처리 및 로깅 형식 수정 (#395) * fix: 리스트 형태의 요청 바디에 null을 넣으면 500이 뜨는 에러 수정 * feat: 로그를 json 형태로 수정 * feat: 로그를 json 인덴트 추가 * refactor: BillActionDetail isFixed 추가 (#405) * fix: 로깅 적용 후 예외 응답 불가 버그 수정 (#413) * feat: 액션 이력 조회 stepName 추가 (#420) * feat: 이슈, PR 템플릿 추가 (#160) (#426) * fix: BillAction 수정시 BillDetail 초기화 안되는 버그 수정 * fix: BillAction 수정시 BillDetail 초기화 안되는 버그 수정 * fix: BillAction 수정시 BillDetail 초기화 안되는 버그 수정 * docs: pr issue close 삭제 * feat: 행사 비밀번호 암호화 추가 (#429) * feat: 행사 비밀번호 암호화 추가 * refactor: 비밀번호 암호화 로직 수정 * fix: MessageDigest를 싱글톤으로 관리하지 않도록 수정 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> * fix: BillActionDetail 초기화시 totalPrice와 정합성 안맞는 버그 수정 (#460) * fix: BillActionDetail 초기화시 totalPrice와 정합성 안맞는 버그 수정 * refactor: BillActionDetail 초기화 로직 BillAction으로 위임 * style: 메소드 이름 수정 * refactor: BillActionDetail 계산 공통 로직 메소드 분리 * fix: price 분배 로직 버그 수정 * style: 미사용 필드 제거 --------- Co-authored-by: Arachneee * refactor: DB 데이터를 drop 할 수 없도록 DB user 권한 수정 (#484) --------- Co-authored-by: 이태훈 Co-authored-by: pakxe , soi-ha , jinhokim98 Co-authored-by: JinHo Kim Co-authored-by: Pakxe Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> Co-authored-by: Soyeon Choe Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> Co-authored-by: Arachneee Co-authored-by: juha Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> Co-authored-by: JUHA <84626225+khabh@users.noreply.github.com> Co-authored-by: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Co-authored-by: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> * fix 행사 인원 이름 변경시 지출 상세의 이름이 변경되지 않는 버그 수정 (#500) * fix: 참여자 이름 변경시 지출 상세 이름 변경 안되는 버그 수정 (#508) * feat: 행동대장 v1.0.0 (#516) * chore: webpack, react, typescript 환경 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 * chore: eslint, prettier 설정 Co-authored-by: JinHo Kim Co-authored-by: Pakxe * docs: pr 템플릿 및 issue 템플릿 세팅 Co-authored-by: pakxe , soi-ha , jinhokim98 * docs: issue 템플릿에 타이틀과 관련된 부가 정보 추가 Co-authored-by: pakxe , soi-ha , jinhokim98 * chore: 모든 install 에 legacy-peer-deps를 사용하도록 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: emotion css props 사용 예제 작성 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: webpack, @emotion/react 라이브러리 설치 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: css props를 사용하기 위해 'jsxImportSource' 옵션 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: css props 사용 위해 모든 파일 최상단에 주석을 자동으로 작성해주도록 플러그인 세팅 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: 개발서버 포트번호 3001 -> 3000 으로 수정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: prettier에서 useTabs를 사용하지 않도록 제거 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: 여러 명이 co-authored-by로 들어갈 수 있는지 테스트 커밋 Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari * chore: 임시로 지웠던 types 옵션을 다시 활성화 Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari * chore: 기본 webpack 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: theme, token 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: storybook 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Button 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Text 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * fix: webpack 설정 entry 파일 확장자 tsx에서 ts로 변경 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: modify-source-webpack-plugin 의존성 반영되지 않은 것 추가 Co-authored-by: pakxe * chore: css파일을 처리하기 위한 webpack 세팅 Co-authored-by: pakxe * design: 기본 css style 초기화 작업 Co-authored-by: pakxe * feat: 메인 페이지 퍼블리싱 Co-authored-by: pakxe * feat: 이벤트 생성 페이지 퍼블리싱 Co-authored-by: pakxe * feat: 이벤트 생성 완료 페이지 퍼블리싱 Co-authored-by: pakxe * design: 전역 스타일링 설정 Co-authored-by: pakxe * feat: 라우터 셋팅 Co-authored-by: pakxe * feat: 앱의 진입점 설정 Co-authored-by: pakxe * feat: 라우트 경로 설정 Co-authored-by: pakxe * fix: 라우트 이동 시 페이지가 제대로 보이지 않던 문제 해결 Co-authored-by: pakxe * feat: 모달 컴포넌트 생성 Co-authored-by: pakxe * feat: 스위치 컴포넌트 생성 Co-authored-by: pakxe * feat: 초기인원 세팅 기능 퍼블리싱 및 구현 Co-authored-by: pakxe * feat: 행동 추가를 위한 모달 컨텐츠 구현 Co-authored-by: pakxe * feat: 지출 내역 관리 기능구현 Co-authored-by: pakxe * feat: 인원 관리 기능구현 Co-authored-by: pakxe * feat: 행사관리 페이지 퍼블리싱 및 구현 Co-authored-by: pakxe * feat: 해커톤 로그 출력을 위한 임시처리 Co-authored-by: pakxe * feat: 프로젝트 초기 설정 * feat: 엔티티 추가 * refactor: gitignore 수정 * refactor: 엔티티 컬럼명 변경 * chore: path alias 설정 및 lint 마이그레이션 * [FE] 해커톤 범위 디자인시스템 구현 (#36) * feat: FixedButton Component 구현 Co-authored-by: soi-ha * feat: Input component 구현 Co-authored-by: soi-ha * feat: Title component 구현 Co-authored-by: soi-ha * feat: BottomSheet component 구현 Co-authored-by: soi-ha * fix: BottomSheet component 빌드 오류 해결 * move: 전체적인 파일 경로 수정정 * move: 전체적인 파일 경로 수정 * fix: npm build를 위한 설정 변경 * feat: IconButton Component 추가 * design: IconButton height가 제대로 적용되지 않는 오류 수정 * feat: npm 배포를 위한 환경설정 및 파일 경로 수정 Co-authored-by: Soyeon Choe * style: eslint 적용 * design: globalStyle root BG 변경 * design: globalStyle background 변경 * fix: Title type 변경 * chore: storybook svg 사용을 위한 main.ts 설정 * feat: BillItem component 구현 * feat: InOutItem Component 구현 * feat: StepItemComponent 구현 * chore: storybook preview background color 수정 * chore: tsconfig.json sourcemap 속성 변경 * chore: npm v0.1.0 배포 --------- Co-authored-by: soi-ha Co-authored-by: Soyeon Choe * feat: CI/CD 파이프라인 구축 (#42) * feat: ci/cd 구축 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * fix: ci/cd 디폴트 경로 변경 * feat: cicd 테스트 객체 제거 * feat: cicd 테스트 객체 제거 * feat: 행사 생성 기능 구현 * feat: 지출 내역 추가 기능 구현 * refactor: event의 마지막 action 순서 조회 로직 수정 * refactor: BillAction fetch type 수정 * test: 불필요한 mocking 제거 * refactor: 중요도에 따라 필드 순서 변경 * fix: BillAction 저장 Dto 검증 추가 * [FE] 디자인 시스템 수정 (#46) * chore: storybook 관련 dependency 설치 * fix: Text component 수정 * feat: TextButton Component 구현 * fix: Title Component 수정 * feat: input component background color InputType 추가 및 입력제거 아이콘 변경 * feat: Switch component 구현 * feat: TopNav component 구현 * feat: Tab 컴포넌트 구현 * refactor: Tab type type.ts로 분리 * feature: ExpenseList component 구현 * design: 폰트 size, weight, color 수정 * feat: BillItem에 드래그핸들러 포함 여부를 props로 받을 수 있도록 구현 * design: 드래그핸들러 여부에 따라 패딩을 다르게 하도록 수정 * feat: Flex 컴포넌트 구현 * feat: 잡고 이동할 수 있는 DragHandleItem 컴포넌트 모습 구현 아직 잡고 이동하는 기능은 없습니다. * chore: DragHandleItem 컴포넌트의 스토리북 작성 * feat: BillItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * feat: InOutItem 컴포넌트가 DragHandleItem, Flex 컴포넌트를 사용하도록 수정 * fix: 스토리북에서 배열 형태로 모습 테스트를 할 수 있도록 type 수정 * feat: InOutItem에서 드래그 여부를 할 수 있도록 type 추가 * feat: StepItem 컴포넌트가 Flex 컴포넌트를 사용하도록 대체 * feat: children을 포함하는 타입을 빠르게 선언하기 위한 타입 구현 * feat: 카멜 케이스를 케밥 케이스의 문자열로 반환하는 함수 구현 * design: 사용하지 않게된 css 객체 제거 * feat: COLORS 자동완성을 위한 타입 추가 --------- Co-authored-by: 김진호 Co-authored-by: Soyeon Choe Co-authored-by: pakxe * refactor: BillAction 검증 로직 수정 * refactor: 지출 내역 추가 로직 수정 * feat: BillAction과 Action cascade 옵션과 orphanRemoval 옵션 변경 * test: event save 로직 분리 * test: DisplayName 변경 Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * test: 경계값 테스트로 변경 Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> * test: 지출 내역 생성 테스트 수정 * feat: PR 후 테스트 리포트 발행 기능 추가 (#56) * test: 미사용 test class 제거 * [BE] 인원 변동 기능 구현 (#47) * feat: 인원 변동 기능 구현 Co-authored-by: kunsanglee * refactor: 메서드 분리 Co-authored-by: kunsanglee * refactor: 코드 컨벤션 Co-authored-by: kunsanglee * refactor: 멤버 액션 생성 클래스 분리 Co-authored-by: kunsanglee * refactor: MemberActionFactory 코드 리팩터링 * refactor: DTO 클래스명 리팩터링 * refactor: MemberActionRepository Lazy Loading 적용 * test: MemberActionFactory createMemberActions 결과 검증 테스트 추가 * refactor: 컨벤션에 맞게 수정 Co-authored-by: kunsanglee * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 Co-authored-by: kunsanglee Co-authored-by: Arachne * refactor: memberActions를 복사해서 내림차순 정렬하도록 수정, 검증 로직 내부로 이동 * refactor: 컨벤션에 맞게 수정 * feat: 사용자 이름이 중복 입력되는 예외 상황 검증 Co-authored-by: kunsanglee Co-authored-by: Arachne * refactor: 메서드 순서 변경 Co-authored-by: Arachne --------- Co-authored-by: kunsanglee Co-authored-by: Arachne authored-by: khabh * [BE] 패키지 구조 변경 (#62) * chore: 패키지 구조 변경 * test: 패키지 구조 변경 --------- Co-authored-by: Arachneee * feat: api wrapping 객체 생성 (#68) Co-authored-by: JinHo Kim Co-authored-by: Pakxe Co-authored-by: Soyeon Choe * [FE] @svgr/webpack 플러그인 설치 * feat: 행사 정보 조회 기능 구현 (#75) Co-authored-by: kunsanglee * [BE] 설정 파일 서브 모듈 생성 (#82) * feat: 설정 파일을 서브모듈로 관리 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: 테스트 설정 파일 추가 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: 도커 파일 내 profile 설정 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * feat: gitflow에 서브 모듈 설정 Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh --------- Co-authored-by: kunsanglee Co-authored-by: Arachne Co-authored-by: khabh * [BE] 요청 데이터가 맵핑되지 않는 문제 해결 (#86) Co-authored-by: kunsanglee Co-authored-by: Arachneee Co-authored-by: khabh * feat: 현재 참여 인원 조회 기능 구현 (#70) * design: 탭 컴포넌트 height 소수점 문제 (#51) * design: tab height 소수점 문제 해결 * fix: tab component after 가상태그를 활용해서 div 태그 제거 * chore: 배포, CI 및 테스트 전략 수립 #32 * chore: frontend-push yaml 파일 추가 * chore: eslint-import-resolver-typescript 추가 * chore: eslint explicit-module-boundary-types 옵션 해제 * chore: noUnused tsconfig.json 설정 제거 * chore: eslint no-use-before-define 옵션 제거 * style: eslint 적용 * fix: workflow yml 파일 수정 * feat: 행사 생성 페이지 구현 (#87) * feat: 행사 생성 페이지 디자인시스템 적용 * design : index.css 수정 * feat: 행사 생성 api 연결 * style: lint 적용 * feat: 행사 홈 페이지 구현 (#88) * chore: env와 디자인 시스템 라이브러리 설치 * chore: 현재 불필요한 옵션 비활성화 * chore: env를 사용하기 위한 환경 세팅 * feat: 디자인 시스템 provider 사용 * design: index.css 정한대로 수정 * feat: apiBaseUrl 선언 * feat: router에 Home 페이지 연결 * feat: api호출 시 매번 들어가는 prefix 상수화 * feat: eventId를 타입에 포함시키기 위한 WithEventId 타입 선언 * feat: 지출 내역 추가 api 구현 * feat: 행사 생성 api 구현 * feat: 참여자 목록 갱신 api 구현 * feat: 정산 현황 요청 api 구현 * feat: 행사 이력 조회 api 구현 * feat: 참여자 별 정산 목록 컴포넌트 구현 * feat: 전체 지출 내역 컴포넌트 구현 * feat: router url 논의된 대로 선언 * feat: 정산 현황 검색을 위한 훅 구현 * feat: 스텝 목록을 관리하기 위한 훅 구현 * chore: 정산 현황 목 데이터 작성 * chore: 전체 지출 내역 목 데이터 작성 * feat: 홈 페이지 레이아웃 구현 * feat: 홈 페이지 안에 들어갈 컨텐츠 구현 * feat: Home -> HomePage로 import 할 수 있도록 export 작성 * feat: 스텝 목록에 필요한 타입 선언 * chore: url 경로 포멧 변경에 따른 수정 * chore: package-lock 업로드 * chore: import 개행 추가 * chore: 디자인 시스템 업데이트 * fix: inOutType 대문자로 넘기도록 수정 * feat: TopNav 추가 * chore: 사용하지 않는 util라이브러리 삭제 * chore: dotenv 세팅 수정 * feat: 현재 참여자 검색 component 생성 (#78) * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: search 컴포넌트 구현 * design: input 컴포넌트 마진 추가로 searchTerms 마진 추가 * refactor: 사용하지 않는 onChange 제거 * refactor: setKeyword -> setState로 setter라는 의미 명시 * style: early return 뒤 개행 추가 --------- Co-authored-by: 이태훈 * feat: CORS 설정 (#90) * feat: CORS 설정 * refactor: CORS 설정 분리 * test: yml에 CORS 설정 추가 * feat: Origin 추가 * feat: Cors 설정에 HTTP OPTIONS 메서드 추가 --------- Co-authored-by: juha * feat: 행사 커스텀 예외 처리 (#92) * feat: 행사 커스텀 예외 처리 * feat: 커스텀 예외 적용 * feat: 참여자별 정산 현황 조회 기능 구현 (#77) * feat: api 명세에서 행사 url을 표현하는 용어와 전달 방식 수정 (#98) * feat: 행사 url 명세를 token에서 eventId로 변경 * feat: 행사 url을 헤더가 아닌 바디로 전달 * test: 행사 생성 컨트롤러 테스트 수정 * feat: 행사 생성 응답 dto에 필드명 수정 * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 (#102) * feat: 기본 프로파일에서 DB를 MySQL을 H2로 변경 * feat: jpa dll-auto none에서 create로 변경 * refactor: 지출 내역 생성 및 현재 참여 인원 조회 예외 메시지 변경 (#100) * refactor: 지출 내역 생성 예외 메시지 변경 * refactor: 현재 인원 조회 예외 메시지 변경 * refactor: 예외 메시지 전달 방법 수정 * refactor: 참여자별 정산 현황 조회 예외 메시지 변경 (#106) * refactor: 행사 생성 API 예외 메세지 및 DTO 검증 애너테이션 추가 (#103) * refactor: 행사 생성 API 예외 메세지 추가 및 DTO 검증 애너테이션 추가 * refactor: 행사 생성 API EventSaveRequest name을 eventName으로 변경 * refactor: 행사 생성 요청 객체 검증 애너테이션 @Size 제거 * refactor: 연속된 공백 검증 및 예외 메세지 상수 사용하도록 리팩터링 * feat: 행사 관리 페이지 구현 (#107) * style: eslint 적용 * chore: typescript with invalid interface loaded as resolver 해결을 위한 eslint-import-resolver-typescript 설치 * chore: SetInitialParticipatns & SetActionModalContent를 Modal의 index.ts에서 export 추가 * design: HDesignProvider 적용 * design: 행사 관리 페이지 퍼블리싱 * design: 초기 인원 설정 Modal 퍼블리싱 * design: 지출내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 Modal 내부 퍼블리싱 * feat: TopNav 추가 및 props 추가 * design: BottomSheet 내부 퍼블리싱 (Input overflow시 scroll) * design: 행사 지출/인원 변동 내역 생성 퍼블리싱 * design: switch와 container의 gap 추가 * design: scroll시 모든 자식 요소가 안 보이는 에러 해결 * design: MainLayout 적용 및 root 태그에 height 적용 * design: 지출 내역 생성 Modal 내부 퍼블리싱 * design: 인원 변동 내역 생성 Modal 내부 퍼블리싱 * chore: develop 브랜치 merge로 인한 수정 * chore: 불필요한 import 삭제 * chore: haengdong-design 버전 업데이트 설치 * remove: 사용하지 않는 파일 제거 * chore: TopNav 수정된 디자인 시스템 설치 및 StepList 수정 주석 추가 * style: lint 적용 * feat: Input 값 입력시 다음 Input이 생성되는 hook 기능 구현 * feat: useDynamicInput에 auto focus 및 scrollIntoView 기능 추가 * feat: 초기 인원 설정 및 인원 변동 내역 Modal에 useDynamicInput 적용 * feat: 지출 내역에 대한 기능 구현 (useDynamicInputPairs 훅 생성) * chore: 불필요한 props 제거 및 backlog 주석 추가 * fix: BottomSheet의 onClick을 통해 submit되는 오류 수정 * fix: setParticipants를 분리하여 참여 인원 관리 * fix: setOrder를 분리하여 지출 내역 차수 관리 * chore: 사용하지 않는 상태 제거 * chore: haengdong-design 버전 업데이트 반영 * fix: 작성된 값을 수정할 수 없는 에러 해결 * chore: 에러 발생 수정에 대한 주석 추가 * chore: 디자인시스템 버전 업데이트 반영 * fix: 예외에서 정의한 메세지를 꺼내지 못하는 오류 해결 (#111) * feat: 퍼블리싱된 페이지 매끄럽게 연결 (#114) * chore: 디자인시스템 업데이트 반영 * feat: fixed button 클릭시 router 반영 * feat: 총 지출 금액 추가 및 StepList 연결 * refactor: 인원 변동 요청 형태 변경 (#117) * feat: 액션 이력 조회 기능 구현 (#76) * feat: 액션 이력 조회 기능 구현 Co-authored-by: 3juhwan <13selfesteem91@naver.com> * feat: 액션 이력 조회 반환 형식 변경 * test: 액션 이력 조회 테스트 삭제 --------- Co-authored-by: 3juhwan <13selfesteem91@naver.com> * chore: frontend yml lint 과정 수정 (#120) * fix: 액션 이력이 없는 경우 빈 리스트 반환 (#122) * fix: 액션 이력 조회 오류 수정 (#124) * fix: HaengdongException 적용 안된 부분 적용 * fix: Transactional 추가 및 StepResponse 로직 수정 * fix: StepResponse 로직 수정 (#126) * test: Gradle, Docker 캐싱을 위한 Feature/#121 test (#128) * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * test * after cache * after cache2 * test: Gardle, Docker 캐싱을 위한 Feature/#121 test2 (#130) * refactor: Github Actions Gradle, Docker Build 캐싱 * refactor: Docker 사용하는 포트 번호 수정 * refactor: Docker 사용하는 포트 번호 수정 * after cache * revert: gradle cache, docker cache (#133) * refactor: 애플리케이션 도커 포트 번호 수정 (#134) * refactor: Docker 빌드 성능 개선 (#138) * refactor: 참여자 정산 현황 로직 리펙토링 (#110) * refactor: 참여자 정산 현황 로직 수정 * refactor: forEach -> stream 변경 * chore: storybook chromatic 배포 (#81) * chore: storybook chromatic workfloe * style: EOL 제거 * chore: storybook 배포를 위한 workflow 설정 * chore: storybook 배포를 위한 workflow 설정 * chore: workflow node 설정 추가 * chore: lint flow path 변경 * chore: run lint 수정 * chore: eslint-config-prettier 추가 * chore: lint 적용 * chore: airbnb 제거 * chore: eslint 설정 수정 * chore: chromatic working directory 변경 * feat: 2차 스프린트 API 연결 (#137) * chore: storybook 관련 dependency 설치 * feat: post api에도 response를 받을 수 있도록 수정 * refactor: parameter가 파스칼케이스인 부분을 카멜 케이스로 수정 * feat: 행사명을 가져오는 api 함수 구현 * feat: interface 수정에 따라 body 변경 * feat: 지출 내역을 추가하는 api 연결 * feat: 최초 참여자를 추가하는 api 연결 * feat: 참여자 수를 조정하는 api 연결 * refactor: name -> title로 파라미터명 수정 * feat: 이벤트아이디를 url에서 불러오는 훅 구현 * feat: 지출 내역, 인원 조정 api연결 후 provider로 전파 * feat: url에서 eventId를 받아오도록 추가 * feat: submit이벤트를 form 엘리먼트에 연결 * remove: 사용하지 않는 파일 제거 * feat: useContext를 사용해 총 가격을 불러오도록 연결 * feat: provider를 사용하기 위한 Layout 컴포넌트 추가 * feat: 디자인시스템 수정에 다른 컴포넌트 호출 형태 변경 * chore: 주석 추가 * remove: 사용하지 않는 파일 제거 * feat: router 에 home, admin 경로에서 띄울 컴포넌트 연결 * fix: 변경된 interface에 맞게 body 수정 * feat: 참여자 목록을 넘겨주지 않고, 참여자 타입 전달 * chore: 불필요한 props 삭제 * feat: 공백된 값 제거 * feat: 네비게이션을 위한 구현 * fix: useStepList훅이 context를 반환하도록 수정 * feat: TopNav 추가 * feat: Admin 페이지 구현 * feat: Home 페이지 구현 * chore: 디자인시스템 라이브러리 업데이트 * chore: await 추가 * feat: stepList를 호출하도록 api 연결 * chore: 사용하지 않는 변수 제거 * chore: lint 적용 * feat: steps를 꺼내서 return하도록 수정 * feat: 인원이 있어야 memberNameList를 갱신하도록 로직 작성 * feat: StepList 의 타입 작성 * design: 불필요한 padding 제거 * chore: 관리 탭에서 StepList를 보여주기 위해 임시로 조건문 제거 * feat: 홈 페이지에서 총 지출 금액 표시 * chore: 디자인 시스템 업데이트 * fix: meta tag 설정 - mixed content, scalable 등 * design: 메인 페이지 및 행사 생성 페이지 디자인 수정 * fix: 새로 고침하면 내역이 출력되지 않는 오류 수정 eventId의 변화에 따라 지출 내역을 다시 호출하도록 종속성을 연결하지 않아서 발생한 문제입니다. * chore: Content-Security-Policy 삭제 * fix: FixedButton disabled 속성 추가 * fix: 행사 이름 입력 페이지 FixedButton disalbed 추가 및 공백 제거 * style: lint 적용 * fix: 불필요한 인자를 넘겨주는 것 제거 * chore: 사용되지 않는 import 제거 * fix: 참여자별 지출 내역을 받아오는 api의 엔드포인트 올바르게 수정 * fix: eventId, 전체 검색 결과에 따라 검색 결과가 보여지도록 수정 * design: 이벤트 홈 타이틀과 탭 사이 공백 제거 * feat: 임시로 행사 이름을 표시하도록 수정 * style: 사용하지 않는 변수 및 import 제거 * design: 전역 스크롤바 숨김 처리 * design: 바텀 버튼만큼 contents 위로 올라오도록 변경 * rename: steList 타입 파일 useStepList 폴더로 이동 후 type.ts로 이름 변경 * chore: 디자인시스템 버전 업데이트 * feat: 검색창 placeholder 참여자 이름 추가 --------- Co-authored-by: 이태훈 Co-authored-by: 김진호 Co-authored-by: pakxe * refactor: 도커 계정 관련 정보 secrets으로 수정 (#139) * feat: 2차 스프린트 디자인 시스템 수정 (#83) * design: Title Component width 100%로 수정 * design: TopNav width 100%로 수정 * fix: index.tsx export 수정 * chore: v0.1.2 배포 * design: input 좌우 1rem 추가 * feat: MainLayout 추가 * chore: v0.1.3 배포 * feat: TopNav none 타입 추가 * chore: storybook-addon-react-router-v6 dev dependency 추가 * fix: ExpenseItem button props 넣을 수 있도록 수정 * design: button cursor pointer 전역설정 * refactor: BottomSheet component 구조 수정 * chore: v0.1.4 배포 * refactor: tab components 합성방식으로 변경 * feat: Flex component backgroundColor 받을 수 있도록 변경 * fix: 주석이 xml 내부에서 적용안되던 오류 해결 * chore: v0.1.5 배포 * refactor: flex background prop 로직 처리 방법 변경 * feat: MainLayout backgroundColor prop 추가 * fix: flex backgroundColor defaultValue 제거 * chore: v0.1.6 배포 * fix: MainLayout margin padding으로 변경 * fix: Switch 및 TopNav 내부 로직 변경 * test: Switch storybook 수정 * fix: TopNav navigate currentPath를 이용하도록 수정 * feat: v0.1.18 배포 * fix: TopNav navigate 변경 * design: tab item과 panel 사이에 gap 넣을 수 있도록 설정 및 flex container 사용 * refactor: in out type uppercase로 수정 * design: in out item font size 변경 및 텍스트 바꿔서 작성한 내용 수정 * test: InOutItem storybook 수정 * chore: v0.1.20 배포 * design: hasDragableItem 비활성화 시 마진 수정 * fix: props 네이밍 스토리북에 반영 * fix: navigate 뒤로가기 3번 발생하는 이슈 해결 * chore: v0.1.22 배포 * fix: Switch 내부의 불필요한 로직 제거 * chore: v0.1.23 배포 * fix: navigate path 로직 변경 * fix: 새로고침 됐을 때 해당 location 페이지를 유지하도록 수정 * style: children이 없는 태그 스스로 닫도록 수정 * style: todo 주석 제거 * chore: v0.1.25 배포 * design: fixedButton position 변경 * chore: v0.1.26 배포 * fix: 라우팅 변경 이동 오류 해결 * chore: v0.1.27 배포 * chore: v0.1.28 배포 * fix: location set 로직을 home 모드에서만 작동하도록 변경 * chore: v0.1.29 배포 * fix: TopNav navigation 로직 외부에서 넣도록 변경 * chore: v0.1.30 배포 * fix: index.ts 경로 문제로 제거 * chore: v0.1.13 배포 * chore: v0.1.32 배포 * fix: Fixed Button 하단 고정되도록 변경 * chore: v0.1.33 배포 * v0.1.35 배포 * fix: 가격과 원을 붙여서 표기 * fix: TopNav가 children이 없어도 작동하도록 변경 * fix: children이 필수가 아니도록 변경 * remove: 사용하지 않는 NavSwitch 제거 * chore: 파이프라인 테스트를 위한 push * chore: 파이프라인 테스트를 위한 push * remove: merge를 위한 /sever dir 삭제 * style: lint 적용 --------- Co-authored-by: 이태훈 Co-authored-by: pakxe * chore: server directory 복구 (#150) * fix: gradlew 권한 버그 수정 (#152) * remove: 서버 코드 삭제 * [FE] 스프린트3 디자인 수정 (#162) * chore: esbuild 설치 및 eslint 업데이트 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * chore: error 및 trash svg 파일 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * design: token color 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * design: Button 컴포넌트 destructive 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * chore: merge로 생긴 불필요한 태그 제거 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: FixedButton 퍼블리싱 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: Input 컴포넌트 focus 및 error시 outline 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: LabelInput 기능 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: Toast 컴포넌트 기능 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: useInput에 focus 기능 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * chore: Toast에서 show를 isShow로 네이밍 변경 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * chore: v0.1.36 배포 * chore: yml 파일 branches를 develop에서 fe-dev로 변경 및 storybook build 명령어 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * style: lint 적용 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> --------- Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> Co-authored-by: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Co-authored-by: 이태훈 * chore: branch 변경에 따른 yml 파일 수정 (#165) * fix: 스토리북 워크플로우 오류 (#168) * fix: 스토리북 배포를 위한 workflow 수정 * fix: develop 브랜치로 트리거하던 걸 fe-dev 브랜치로 수정 * chore: 스토리북을 배포한 사람의 아이디를 출력하도록 수정 * feat: 토스트 생성 (#166) * feat: Toast 컴포넌트에 position 추가 * feat: 되돌리기 버튼과 클릭했을 시 닫히도록 하는 기능 추가 Co-authored-by: JinHo Kim * design: 두 개의 svg로고가 같은 크기, 중앙 정렬을 갖도록 svg 파일 수정 * feat: 토스트의 타입, 되돌리기 유무, 닫힘 콜백 타입 추가 * design: isShow로 토스트를 켜고 끄지 않도록하고 마진 수정 * remove: ToastProvider에 합쳐진 파일이므로 제거 * test: 다양한 모습의 토스트를 스토리북으로 시연 * feat: 토스트를 사용하기 위한 Provider와 hook 구현 * test: ToastProvider를 시연하기 위한 스토리북 작성 * feat: Toast, ToastProvider, useToast export * chore: package-lock.json 업데이트 * design: 버튼의 내부 텍스트가 줄넘김 되지 않도록 css 추가 * test: Toast 스토리북 message 수정 * feat: Toast default position을 bottom으로 셋팅 * chore: lint 적용 Co-authored-by: JinHo Kim Co-authored-by: Soyeon Choe --------- Co-authored-by: pakxe Co-authored-by: JinHo Kim Co-authored-by: Soyeon Choe * fix: client 디렉토리 reset, 전역 스타일 GlobalStyle을 사용하는 것으로 변경 (#173) * refactor: css를 global style로 수정 Co-authored-by: Pakxe * refactor: global style app과 index에 적용 Co-authored-by: Pakxe * chore: css 파일을 읽기 위한 의존성 삭제 Co-authored-by: Pakxe --------- Co-authored-by: Pakxe * design: Button이 disabled일 때 커서가 포인터가 아니도록 수정 (#171) * feat: Input 컴포넌트 관련한 기능 수정, useDynamic-* 훅 관련 오류 수정, 네이밍 통일, 의미를 명확하게 담도록 네이밍 수정 (#143, #183) * chore: hdesign v0.1.37 배포 Co-authored-by: Soyeon Choe * remove: 사용하지 않는 코드 제거 * feat: v0.1.44 배포 input 변경 Co-authored-by: Soyeon Choe * refactor: event/create 페이지 input 작동 방식 변경 및 새로운 input 적용 * design: Input outline boxshadow로 변경 및 우선순위 조정 * feat: 초기 멤버 설정 modal 내의 input 동작 방식 변경 Co-authored-by: Soyeon Choe * feat: LabelInput, LabelGroupInput 등 다양한 Input Component 생성 Co-authored-by: Soyeon Choe * fix: 공백이 존재하는 input 제거 * style: lint 적용 * style: lint 적용 * chore: v0.1.47 배포 * feat: v0.1.49 배포 input sync가 제대로 맞지 않던 오류 수정 errorMessage 제대로 적용되지 않던 오류 수정 Co-authored-by: Soyeon Choe * feat: v0.1.51 배포 * feat: DynamicInput 수정 및 유효성 검사 추가 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: 충돌 병합 * feat: v0.1.52 디자인시스템 배포 * fix: 다음 입력을 기대하는 인풋이 뜨도록 하고 중간 인풋을 삭제했을 때 input 엘리먼트 자체가 사라지도록 구현 * rename: SerPurchase -> AddBillActionListModalContent로 이름 변경 * rename: UpdateParticipants -> AddMemberActionListModalContent 로 이름 변경 * rename: SetPurchase -> SetActionListModal 로 이름 변경 * rename: SetInitialParticipants -> SetInitialMemberListModal 로 이름 변경 * feat: enter가 눌렸을 때 실행할 로직을 훅 안으로 이동 * fix: 0, 1번만 있을 때 2개의 빈 잇풋 엘리먼트가 남아버리는 문제 해결, handleBlur -> deleteEmptyInputElementOnBlur 로 기능을 드러내는 함수명으로 변경 * feat: canSubmit 상태를 관리하는 로직을 함수로 분리 * refactor: 현재 변화중인 targetInput을 가져오는 반복되는 로직을 분리, 선언되어있는 함수 순서를 useEffect, on-* props에 장착되는 함수, 유틸성 함수로 정리 * rename: pages안의 파일에 전부 -Page 를 붙여 컴포넌트 성격을 잘 드러낼 수 있도록 이름 변경 * fix: 인덱스틀 사용해 인풋 쌍을 관리하도록 수정. 인덱스를 사용함에 따라 모든 함수도 인덱스를 사용하도록 수정 * feat: pair당 하나의 인덱스를 갖지만, input element는 두 개이므로 정확한 input element특정을 위해 인덱스를 계산해 focus를 넘겨주도록 구현 * rename: 해당 파일에 이미 도메인과 깊게 얽힌 코드가 내장되어 있으므로 의미를 더 드러내는 이름으로 변경. useDynamicInputPair -> useDynamicBillActionInput * chore: Modal 폴더 내의 이름 변경으로 인해 생긴 import 변동 사항 * fix: 함수가 state를 사용하지 않도록 수정 * feat: type.d.ts에 있던 내용을 옮겨옴 * chore: import 경로 수정 * chore: package-lock 업데이트 * design: Input에 css props 적용 * refactor: 리뷰 반영 Co-authored-by: Soyeon Choe Co-authored-by: Pakxe Co-authored-by: jinhokim98 * refactor: 리뷰 반영 Co-authored-by: Soyeon Choe Co-authored-by: Pakxe Co-authored-by: jinhokim98 * style: lint 적용 Co-authored-by: Soyeon Choe Co-authored-by: Pakxe Co-authored-by: jinhokim98 * fix: Toast 2번 import 되던 오류 수정 * chore: yml workflow 수정 * chore: client pr workflow 수정 * chore: client workflow 수정 * chore: workflow 수정 --------- Co-authored-by: 이태훈 Co-authored-by: Soyeon Choe Co-authored-by: Soyeon Choe Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> Co-authored-by: Pakxe Co-authored-by: jinhokim98 * feat: 변경된 API endpoint로 수정 (#196) * feat: 변경된 API endpoint로 수정 Co-Authored-By: Pakxe <64801796+pakxe@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * chore: 디자인시스템 버전 업데이트 Co-Authored-By: Pakxe <64801796+pakxe@users.noreply.github.com> Co-Authored-By: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> --------- Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> Co-authored-by: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: 디자인시스템 hover, mouse, transition animation (#198) * fix: input delete button onMouseDown 으로 변경 * feat: input 및 button active 속성 추가, input focus 관련 버그 수정 * fix: conflict 해결 * fix: transition이 중복되어 작성된 오류 수정 * feat: v0.1.54 배포 * style: lint 적용 * design: input label text에 transition 적용되도록 구조 변경 * design: BottomSheet 전환에 따른 animation 적용 * chore: v0.1.55 배포 * chore: HDesign workflow run-name 수정 * chore: @swc/chore 설치 * feat: BottomSheet handler drag 추가 * style: drag threshold 상수화 * style: 중복되는 css 로직 분리 * style: :not 선택자 공통 부분 묶어서 수정 * style: onClose, onOpen 함수명 변경 * [FE] ListButton component 생성 (#203) * fix: input delete button onMouseDown 으로 변경 * feat: input 및 button active 속성 추가, input focus 관련 버그 수정 * fix: conflict 해결 * fix: transition이 중복되어 작성된 오류 수정 * feat: v0.1.54 배포 * style: lint 적용 * design: input label text에 transition 적용되도록 구조 변경 * design: BottomSheet 전환에 따른 animation 적용 * chore: v0.1.55 배포 * chore: HDesign workflow run-name 수정 * chore: @swc/chore 설치 * feat: BottomSheet handler drag 추가 * feat: ListComponent 생성 * style: drag threshold 상수화 * style: 중복되는 css 로직 분리 * style: :not 선택자 공통 부분 묶어서 수정 * style: onClose, onOpen 함수명 변경 * feat: 개별 ActionItem 컨트롤을 위한 StepItem 및 BillItem / InOutItem component 구조 변경 (#211) * chore: greenColor token 추가 * remove: 사용하지 않는 svg 삭제 * fix: 지난번 변경사항이 반영되지 않은 문제 해결 * fix: 동적으로 변경되는 color를 사용하기 위해 svg 내 fill 및 stroke attribute를 currentColor로 설정 * feat: Icon component 구현 * feat: IconButton Component 구현 * fix: DefaultColor가 제대로 적용되지 않던 오류 수정 * fix: StepItem prop type이 잘못 지정된 오류 수정 * style: lint 적용 * fix: size prop optional로 변경 * test: IconButton storybook props 변경 * fix: 사용하지 않는 css svg 속성 제거 * fix: Icon 위아래 정렬이 맞지 않는 오류 수정 * fix: confirm, error Icon이 제대로 export 되어있지 않던 오류 수정 * feat: Icon, ListButton export * refactor: Icon / IconButton 변경으로 인한 기존 코드 이에 맞게 변경 * fix: 잘못 사용된 주석 변경 * style: lint 적용 * chore: v0.1.57 배포 * feat: DragHandleItem이 BillItem, InOutItem의 역할을 대체할 수 있도록 구조 변경 * remove: 필요하지 않은 BillItem 및 InOut component 제거 * feat: StepItem의 역할을 대신 할 DragHandleItemContainer component 구현 * remove: 필요하지 않은 StepItem component 제거 * test: IconButton component storybook children 변경 * style: lint 적용 * chore: v0.1.58 배포 * feat: 삭제 아이콘을 위한 IconButton component 수정 (#209) * chore: greenColor token 추가 * remove: 사용하지 않는 svg 삭제 * fix: 지난번 변경사항이 반영되지 않은 문제 해결 * fix: 동적으로 변경되는 color를 사용하기 위해 svg 내 fill 및 stroke attribute를 currentColor로 설정 * feat: Icon component 구현 * feat: IconButton Component 구현 * fix: DefaultColor가 제대로 적용되지 않던 오류 수정 * fix: StepItem prop type이 잘못 지정된 오류 수정 * style: lint 적용 * fix: size prop optional로 변경 * test: IconButton storybook props 변경 * fix: 사용하지 않는 css svg 속성 제거 * fix: Icon 위아래 정렬이 맞지 않는 오류 수정 * fix: confirm, error Icon이 제대로 export 되어있지 않던 오류 수정 * feat: Icon, ListButton export * refactor: Icon / IconButton 변경으로 인한 기존 코드 이에 맞게 변경 * fix: 잘못 사용된 주석 변경 * style: lint 적용 * chore: v0.1.57 배포 * test: storybook에서 Icon component가 잘못 사용되던 오류 수정 * refactor: style prop이 여러개인 경우, 객체를 통해 prop 전달하도록 변경 * fix: svg 파일 변경 * feat: 멤버 액션 삭제 기능 구현 + 바뀐 디자인시스템 적용 (#214) * chore: 역할 체인지 위한 저장 * feat: 들어온 인원 삭제 기능 구현 Co-authored-by: JUHA Co-authored-by: Arachne * feat: StepList에 사용되는 타입 파일 작성 * refactor: 전역 타입 선언을 types 디렉토리에서 import하는 형식으로 변경 * refactor: type 관리 변경으로 인한 import 추가 * refactor: Step 내부를 Bill과 Member로 나눔 * fix: 타입 import types 디렉토리로 옮기면서 import 누락 수정 * refactor: member action 훅으로 분리 * refactor: evenPageLayout 파일이름 오류 수정 * refactor: 머지 중 발생한 잔재 처리 * chore: dev dependency로 옮겨야 할 것 옮김 * refactor: index.ts 정의 및 props 이름 변경 * remove: 사용하지 않는 파일 제거 * refactor: index.ts를 통해 import문 줄임 * refactor: 사용하지 않는 타입 제거 * remove: 사용하지 않는 action 함수 제거 * refactor: get out member modal 사용하지 않는 파일로 인해 오류 터지는 현상 해결 * fix: 잘못된 import 수정 -> 새로 만들어진 멤버삭제 api로 연결 * remove: 사용하지 않는 컴포넌트 제거 Co-authored-by: Pakxe * feat: 인원 삭제 모달 구현 Co-authored-by: Pakxe * fix: 행동디자인 props 변경으로 인한 수정 Co-authored-by: Pakxe * chore: 행동디자인 최신버전 반영 Co-authored-by: Pakxe * feat: 토스트 사용하기 위한 provider 적용 Co-authored-by: Pakxe * feat: 삭제 모달에 현재 인원 숫자 표시 * feat: 삭제 요청 도중 오류가 났을 때 토스트모달 보여주는 기능구현 Co-authored-by: Pakxe * fix: 에러일 때 error가 throw되도록 수정 * chore: 행동디자인 버전 업데이트 반영 * feat: 다른 차수에 동일한 인원의 액션이 있을 때 삭제 시 경고창을 띄우는 기능 구현 * fix: 행동디자인 변경으로 인해 그에 맞는 새로운 컴포넌트로 변경 * fix: 인덱스가 0일 때 알림을 주지 않았던 현상 해결 * refactor: 행동디자인을 적용하면서 사용하지 않는 스타일 제거 * feat: confirm에서 에러토스트로 변경 (누가 사라져요), 삭제 시 바텀시트 닫히는 기능 구현 * feat: 행동디자인 변경에 따른 BillStepItem 반영 Co-authored-by: Soyeon Choe * style: 안 쓰는 import문 제거 * chore: stepList mock 데이터 변경 * remove: 없어진 inoutitem 반영 --------- Co-authored-by: pakxe Co-authored-by: JUHA Co-authored-by: Arachne Co-authored-by: Pakxe Co-authored-by: Soyeon Choe * fix: FixedButton의 delete button type "button"으로 변경 (#234) * fix: fixedButton의 delete button type button으로 변경 * design: 잘못 적용된 large size 디자인 적용 * fix: IconButton 및 Icon 생성에 따라 내부 구조 변경 * chore: v0.1.60 배포 * feat: 행사생성 flow에서 admin 접근을 위한 비밀번호를 입력받는 기능 추가 (#226) * remove: 중복되는 코드 삭제 * feat: requestPostNewEvent에 password 정보를 보내도록 수정 * fix: SetEventNamePage에서 api를 호출하지 않고, password page로 이동하도록 수정 * feat: SetEventPasswordPage 구현 * fix: 새로 생긴 page에 router가 대응할 수 있도록 수정 * style: lint 적용 * fix: cookie가 제대로 전달되지 않던 오류 수정 * feat: 지출 액션 수정, 삭제 기능 구현 (#230) * feat: 지출액션 수정 삭제 모달 퍼블리싱 * feat: 각 input에 에러 정보를 주기 위한 필드추가 * chore: 다른 곳에서 사용하게 되어서 export 사용 * feat: 지출액션 수정 기능 구현 * feat: 지출액션 삭제 기능 구현 * chore: 최신 행동디자인 버전 반영 * feat: 지출액션 삭제 후 바텀시트 닫기 기능구현 * style: 명시적 형 변환 사용 * refactor: element key 수정 * refactor: 에러메시지 상수화 * refactor: 시멘틱 태그 header -> h2로 바꿉니다 * design: 바텀시트 스타일 변경 * design: 삭제멤버 모달도 올바른 스타일 적용 * feat: 전체 참여자 BottomSheet 내부 디자인 퍼블리싱 (#228) * feat: ListButton 추가 및 디자인, ListButton 클릭시 BottomSheet 띄우기 * chore: css 컴포넌트 upperCase로 되어있는 것 camelCase로 변경 * design: BottomSheet 내부 Title 퍼블리싱 * design: Input과 DeleteButton 퍼블리싱 * design: FixedButton 추가 및 overflow를 위한 paddingBottom 추가 * feat: 초기 인원 설정이 완료되어야 ListButton이 렌더링되도록 변경 * design: 삭제하기 버튼의 size를 css가 아닌 props size로 사용하기 * style: openBottomSheet 상태명을 isOpenBottomSheet로 변경. 외에도 FixedButton BottomSheet와 전체 참여자 BottomSheet 상태명 상세히 변경 * style: InputAndDeleteButton 컴포넌트 파일 분리 * style: ModalBasedOnMemeberCount 파일 분리 * feat: api에러 등의 에러를 잡아 핸들링 (#232) * chore: ErrorBoundary사용 시 에러가 뜨지 않도록 overlay 속성 끔 * feat: 에러 상태를 전역적으로 관라하기 위한 훅과 컨텍스트 구현 * feat: ErrorProvider가 ToastProvider를 감싸도록 작성 * feat: api 콜할 때 이 useFetch훅을 사용해 전역상태로 만들어준 에러를 핸들하도록 구현 * chore: 임시로 만들어둔 useFetch사용 예시 * chore: useFetch의 request에 넘겨주기 위한 response 타입 export * feat: Toast를 수정해 사용하기 위해 임시로 가져옴 * feat: 전역 에러를 옵저빙하면서 에러가 있다면 토스트를 띄우도록 기능 추가 * fix: 타입에 이름이 일치하지 않는 부분 수정 * feat: 서버 에러 code와 에러 메세지를 매칭하는 상수 구현 * chore: msw, react-error-boundary 설치 * chore: 브라우저 환경에서 msw를 사용하기 위한 세팅 파일 설치 * feat: msw를 앱 시작 지점에 연결 * test: 테스트를 위한 간단한 post 모킹 함수 구현 * feat: 핸들되지 않는 에러 또는 지정되지 않은 path로 이동시 보여줄 에러 페이지 구현 * feat: 불필요한 state제거와 type narrowing * feat: 다뤄지지 않는 에러가 발생했을 시 외부로 에러 던지기 * feat: 핸들되는 에러 판단을 위한 함수 구현 * feat: 불필요한 state, setTimeout제거 * feat: 지정되지 않은 path로 이동 시 에러 페이지 띄우도록 함 * feat: 반복되는 숫자 상수화와 불필요한 jsx 주석 제거 * feat: 잡아서 다루지 않는 에러를 위한 에러 바운더리 컴포넌트 구현 * chore: 불필요하게 사용되는 contentType관련 코드 제거 * feat: Toast에 showingTime을 전달해 애니메이션을 지속 시간만큼 유지할 수 있도록 함 * feat: 에러를 일정 시간 후에 초기화하는 책임을 useError에 위임 * feat: 알 수 없는 에러에 대한 에러 메세지와 이름 작성 * feat: 이벤트를 새로 생성하기 위한 api콜을 담당하는 useEvent훅 구현 * feat: useEvent를 사용해 이벤트를 생성하도록 수정 * chore: 불필요한 import 제거 * chore: msw, react-error-boundary 라이브러리 설치 * chore: 사용하지 않는 import와 주석 제거 * refactor: queryFn -> queryFuntion으로 프로퍼티명 변경 * design: Toast 디자인 수정 * chore: msw를 사용하는 코드 주석 처리 * chore: 린트 적용 * fix: /가 하나 더 들어가있던 부분 수정 * fix: 함수가 아닌 객체로 수정 * design: px to rem * refactor: 불필요한 useCallback제거 * chore: fadeIn -> fadeInWithTransformY 식으로 이름 변경 * chore: 빌드 환경 prod와 dev로 구분 (#217) * chore: env.prod, env.dev 를 위한 gitignore 수정 * chore: dev, prod 환경의 공통 설정을 webpack.common.mjs 로 분리 * chore: dev, prod 환경에 따른 webpack 설정을 위해 webpack.dev.mjs, webpack.prod.mjs 생성 * remove: 사용하지 않는 webpack.config.js 파일 제거 * chore: webpack-merge dependency 설치 * chore: package.json 스크립트 수정 * fix: webpack devserver overlay 적용 * fix: webpack.common.mjs 수정 * fix: merge를 통해 발생한 에러 해결 (#246) * fix: setOpenBottomSheet 이름 변경되지 않아 발생한 충돌을 setIsOpenBottomSheet로 변경하여 해결 * chore: msw 사용을 위한 코드 주석처리 * fix: requestPost에서 contentType 분기 삭제로 인해 에러 발생한 것을 분기 추가하면서해결 * fix: input value 수정이 되지 않는 문제 (#253) * fix: propsValue가 변했을 때 value가 수정되도록 수정 * chore: v0.1.61 publish --------- Co-authored-by: 이태훈 * fix: useToast 에러바운더리 문제 해결 (#264) * fix: 디자인시스템 Text 컴포넌트 color prop 받도록 변경 (#257) * refactor: Text Component color prop 받도록 수정 * fix: Text가 사용된 component에 color prop 사용 * chore: v0.1.62 배포 * fix: Text component의 color prop을 textColor로 변경 * chore: v0.1.63 배포 * style: lint 적용 * fix: 디자인시스템 Input value 동기화 오류 수정 (#266) * fix: useInput에 value dependency를 받도록 설정 * chore: v0.1.65 publish * fix: 행동디자인 Search 컴포넌트 기능 제거 (#260) * feat: Search 컴포넌트 검색 기능을 빼서 연관검색어 작동만 하도록 수정 * refactor: term =>match 이름 변경 반영 * feat: 행사 생성 완료 페이지 유저 친화적으로 변경 (#271) * chore: react-copy-to-clipboard dependency 설치 * feat: 행사 링크 복사 기능 구현 * style: lint 적용 * design: toast 위치 변경 * feat: 인원 탈주 시 인원 검색 기능 구현 (#270) * feat: 인원 검색 시 현재 참여 인원 중에서 검색 후 클릭 시 input에 입력되는 기능 구현 * chore: 새로운 행동디자인 버전 반영 * feat: Search 컴포넌트를 이용한 검색기능 구현 * refactor: 훅 반환타입 명시 * feat: 인원 탈주시에만 검색창이 뜨도록 설정 * style: css 불필요한 함수 스타일 제거 * fix: 행동디자인 Search와 props 수정 * chore: 해결된 todo 주석 제거 * refactor: terms => match 이름 변경으로 인한 리팩토링 --------- Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: 전체 참여자 데이터 요청하고 출력하기 (#250) * feat: requestGetAllMemberList 전체 참여자 조회 요청 함수 생성 * feat: useStepList에 전체 참여자 조회 요청 함수 사용하여 allMemberList 상태에 저장하여 ListButton에 출력하기 * chore: 필요하지 않은 memberNameList(현재 참여자) 삭제 * chore: 이전 커밋에서 삭제된 상태(memberNameList) 대신에 전체 참여자 상태 (allMemberList)로 변경 * feat: get한 전체 참여자 인원을 각 Input에 출력 * chore: ModalBasedOnMemberCount 컴포넌트를 Modal/index.ts에 추가 --------- Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: 전체 참여자 이름 수정 및 삭제 (#276) * feat: requestGetAllMemberList 전체 참여자 조회 요청 함수 생성 * feat: useStepList에 전체 참여자 조회 요청 함수 사용하여 allMemberList 상태에 저장하여 ListButton에 출력하기 * chore: 필요하지 않은 memberNameList(현재 참여자) 삭제 * chore: 이전 커밋에서 삭제된 상태(memberNameList) 대신에 전체 참여자 상태 (allMemberList)로 변경 * feat: get한 전체 참여자 인원을 각 Input에 출력 * chore: ModalBasedOnMemberCount 컴포넌트를 Modal/index.ts에 추가 * chore: 디자인시스템 버전 업데이트 * chore: 디자인시스템 업데이트로 인해 propsValue의 이름을 value로 변경 (이전에는 사용하지 못했음) * feat: 전체 참여자 이름 수정 api 함수 생성 * feat: 전체 참여자 삭제 api 함수 생성 * remove: 불필요한 props drilling으로 인해 파일 분리 삭제 * feat: useSetAllMemberList 훅 생성 & 참여자 이름 변경하는 handleNameChange 생성 (BottomSheet를 닫으면 초기화됨) * feat: 전체 참여자 이름 변경 handleNameChange 구현 * feat: 전체 참여자 이름 삭제 handleClickDeleteButton 기능 생성 * chore: 디자인시스템 업데이트 및 console.log 제거 * feat: 전체 참여자 인원 삭제 api 요청에서 에러가 발생하면 setState를 실행하지 않도록 변경 * chore: 디자인시스템 버전 업데이트 * feat: 참여자 삭제시 리렌더링 시켜주기 * feat: allMemberListBottomSheet를 닫는 함수 훅에 넘겨주기 * fix: toast가 BottomSheet보다 z-index보다 아래여서 띄워지지 않는 에러 발생. z-index 추가 * feat: api 요청시 errorToast 띄워지도록 추가 * feat: input에서 에러 발생시 에러 메세지를 띄우기 & 에러가 발생한 Input에만 에러 테두리 적용 * chore: 참여자 이름 maxLength를 8에서 4로 수정 * feat: 초기 참여자 이름과 현재 참여자 이름을 비교하여 변경된 사항만 서버로 요청하기 * feat: 변경사항이 존재하지 않을 경우 FixedButton일 경우 disabled 기능 구현 * style: 인원수 출력 Text 컴포넌트에 그레이 컬러 추가 * chore: 불필요한 console.log 삭제 * fix: 불필요한 color props 삭제 --------- Co-authored-by: 이태훈 * feat: sentry 적용 (#262) * feat: useStepList훅에서 useFetch함수를 사용하여 에러에 대한 책임을 위임 * chore: sentry 사용을 위한 진입점 파일 세팅 * chore: sentry 라이브러리 설치 * chore: sentry env 파일 ignore 추가 * chore: sentry 관련 라이브러리 설치 * chore: 웹팩에 sentry 플러그인 추가 * feat: 다뤄지지 않는 에러에 대한 조건 추가 * chore: sentry 사용을 위한 진입점 파일 수정 * feat: 에러 로그 전송을 위해 에러 정보들을 담은 FetchError 클래스 구현 * chore: 세미콜론 추가 * feat: 에러 발생시 에러 정보를 갖고 있는 FetchError를 throw하도록 수정 * feat: 에러 코드에 맞게 level을 설정해 sentry에 보내는 함수 구현 * feat: sentry 에 endpoint, url, errorCode, message, status, requestBody 로그를 담아 보내는 함수 구현 * feat: 에러를 잡아 sentry로 보낼 수 있도록 catch에서 sentry 로그 함수 호출 * chore: 불필요한 타입 선언 제거 * fix: Primitive타입만 tag의 value에 넘겨줄 수 있으므로 객체를 JSON문자열로 바꿔 넘겨주도록 수정 * feat: FetchError가 Error의 타입을 상속하도록 함 * chore: lint 적용 * fix: body파라미터를 문자열 타입으로 변경 * chore: alert를 띄우지 않기 위해 주석처리 * chore: errors폴더를 alias 에 추가 * feat: UNHANDLED_ERROR -> UNKNOWN_ERROR로 에러 상수 변경 * feat: 다루지 못하는 에러인 경우 에러를 다시 포장하지 않고 그대로 에러바운더리로 던지도록 수정 * chore: 불필요해보이는 코드 주석처리 * feat: 언노운 에러도 sentry에 에러를 보내도록 추가 * feat: 에러 이름을에는 errorCode만 넣도록 수정 * chore: 불필요한 코드가 삽입되어있는 부분 제거 * feat: FetchError에 status 필드 추가 * chore: sentry로 status도 보내도록 추가 * chore: 린트 적용 --------- Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: 3차 데모데이 merge 중 발생한 문제 수정 (#280) * fix: merge 오류 해결 * fix: 누락된 파일 추가 --------- Co-authored-by: 이태훈 * feat: requestPost에 대해 response가 있는 post와 없는 post로 분기해 사용하도록함 (#281) * fix: merge 오류 해결 * fix: 누락된 파일 추가 * feat: requestPost를 리스폰스가 있는 post와 리스폰스가 없는 post로 분리 * chore: 린트 적용 --------- Co-authored-by: 이태훈 * feat: 홈에서 액션 수정 삭제 바텀시트 활성화 버그 (#285) * style: key props index외 다른 값 추가 * style: children 없는 태그 스스로 닫도록 설정 * fix: 홈에서 액션 수정 삭제 되지 않도록 설정 * feat: cookie가 없는 경우 비밀번호 입력 페이지로 이동 (#286) * feat: ConfirmPasswordPage 구현 * feat: api 연결 * fix: 로그인 시 오류가 발생하던 문제 해결 * fix: 잘못 삭제된 sentry 설정 복구 * style: lint 적용 * style: lint 적용 * feat: 데모데이를 위해 페이지 약간 수정 (#289) * chore: 데모데이 시연을 위해 페이지 약간 수정 * chore: 린트 적용 * fix: import 가 안되어있는 부분 수정 (#293) * fix: 인원 탈주 검색 인풋 오류 (#299) * fix: key를 단순 index로 고치니 해결되네 meet in 커밋메시지에 이렇게 적고 싶지 않았는데 개화나서 적음 * fix: 여러개 한 번에 보이던 문제 해결 * style: console log 제거 * fix: 커밋 잘못 올려서;; 여러 개 한 번에 보이는 문제 해결 * chore: hooks폴더 구조 정리 (#312) * fix: import 가 안되어있는 부분 수정 * chore: 윈도우에서도 동작하는 lint 명령어로 수정 * chore: hooks폴더 안의 내용물을 폴더 밖으로 빼냄 * chore: lint 적용 * chore: lint 적용 * chore: @sentry/react 라이브러리 설치 * feat: 전체 참여자 수정 및 삭제 수정 (#315) * feat: 두 배열이 동일한 값인지 비교하는 util 함수 생성 * feat: 수정완료를 클릭해야 삭제 api 요청이 실행되도록 로직 변경 * fix: 삭제 상태 반영으로 인해 nameChange api 요청의 index가 맞지 않는 에러 해결 * feat: 차수 멤버 확인, useFetch 확장, BottomSheet 활성화 수정 (#311) * feat: 드래그핸들아이템컨테이너 상하좌우 텍스트 onClick 메서드 연결 및 우측 위 텍스트 스타일 변경 * feat: 차수 멤버 확인 기능 퍼블리싱 및 구현 * refactor: 차수 event layout에서 outlet context로 내려주는 방식으로 변경 * refactor: 차수 이름 생성 책임 백엔드로 위임 * feat: useFetch onSuccess, onError 기능 추가 * design: 멤버삭제 모달 텍스트 컬러 수정 * refactor: useFetch queryFunction 객체형으로 수정 및 useFetch 적용되지 않았던 부분 적용 * fix: 오류 시 모달 닫히지 않도록 설정 및 멤버 삭제 실패 시 상태 원복 * fix: 입력이 없을 때 bottom sheet 활성화되던 현상 해결 * feat: 지출액션 추가할 때 요청 성공 시 모달이 닫히도록 설정 * feat: 참여 인원 확인 임시 버튼 삭제 (#318) * fix: export default 인데 중괄호가 있었던 문제 해결 * feat: 인원수를 누를 때 현재 지출 참여인원을 확인할 수 있도록 변경 * chore: 행동디자인 최신버전 반영 * feat: bottomSheet maxWidth 768px 되도록 변경 (#321) * feat: 메인, 관리 페이지 설명 글 수정 (#324) * chore: svg 파일 인식을 위한 declare * feat: Logo asset 추가 및 컴포넌트 생성 * feat: 메인페이지 설명 수정 및 로고 적용 * feat: 어드민 페이지 초기 설정 마무리되면 설명문 변경되도록 설정 * fix: useDynamicInput 버그 수정 (#327) * fix: 행사 참여자 글자수 제한 변경에 따른 errorMessage 수정 * feat: 에러가 발생한 Input에 에러 테두리 출력 및 반복 코드 함수화 * feat: input의 값이 빈배열인지 확인하는 함수 trim으로 구분 * fix: 새로운 input 생성 조건에 현재 Input의 value가 빈 문자가 아닐때 추가 * chore: getFilledInputList 수정으로 인해 불필요한 코드 삭제 * feat: useDynamic을 사용하는 컴포넌트에 error 테두리 적용 * feat: useDynamicInput 수정에 맞게 useDynamicBillActionInput 수정 * chore: console.log 삭제 * feat: 홈 및 관리 페이지에서 링크 복사 기능 추가 (#329) * chore: v0.1.69 배포 * chore: HDesign 신규 버전 적용 * 실행 환경에 따라 복사하는 url 다르게 적용되도록 변경 * feat: eventPageLayout에서 링크 복사하기 기능 추가 * refactor: adminPage, homePage에서 eventName, eventId를 호출하지 않도록 변경 * style: lint 추가 * fix: "정산 초대하기"에서도 실행 환경에 따라 링크가 변경되도록 수정 * fix: 공통된 곳에서 사용되는 문자열 변수에 저장 * design: toast bottom 높이 추가 --------- Co-authored-by: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> * feat: pr issue close workflow 생성 (#328) * test: cypress 적용 및 행사 생성 flow e2e 테스트 작성 (#331) * chore: cypress 설정 Co-authored-by: JinHo Kim * test: 이벤트 생성 cypress 테스트 코드 작성 Co-authored-by: JinHo Kim * chore: cypress workflow 추가 * chore: dev 환경에서 eval source map 사용하도록 변경 * chore: cypress 명령어 세분화 * chore: cypress workflow 추가 * chore: 사용하지 않는 코드 제거 * chore: 사용하지 않는 dotenv 제거 * test: interceptAPI command 작성 * test: 반복되는 테스트 코드 매직넘버 상수화 * chore: postEvent fixture 생성 * test: API 요청이 필요한 부분 intercept * style: 불필요한 주석 제거 --------- Co-authored-by: JinHo Kim * fix: 토큰이 없을 때, 관리페이지로 이동하면 오류가 발생하는 부분 수정 (#338) * feat: url을 통해 eventId를 분리하는 util 함수 구현 * refactor: useEventId를 사용하던 부분 getEventIdByUrl 함수로 대체 및 공백문자 분기처리 제거 * remove: 필요하지 않은 코드 제거 * style: lint 적용 * fix: stepList가 제대로 초기화되지 않는 오류 수정 * fix: 함수 이름 수정 * fix: regexp constants로 분리 * fix: 인원 탈주 추가 시 disable 버그 (#339) * style: 검색어 클릭 시 input set 함수 이름 변경 * fix: can submit 호출 시점 변경 * feat: Sentry prod 환경에서만 돌아가도록 fetcher 설정 (#343) * chore: typescript에 NodeEnv 환경설정 타입 선언 * chore: Sentry 캡쳐 에러를 prod 환경에서만 실행되도록 설정 * refactor: captureError에서 early return 방식으로 변경 * feat: 환경 변수 타입 선언 (#345) * chore: env key 타입 선언 * refactor: env type 선언으로 인한 빈 문자열 대체 제거 * refactor: NODE_ENV 타입 선언으로 빈 문자열 제거 및 development 환경 바로 비교 * refactor: 이벤트 페이지 url 자주사용되는 로직 유틸로 분리 --------- Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> * feat: useDeleteMemberAction 토스트 함수 결합도 제거 (#347) * refactor: useDeleteMemberAction 토스트 로직 UI 컴포넌트로 이동 * refactor: isExistSameMember 함수 훅 외부로 넘겨주지 않고 특이한 케이스를 검사하는 함수를 훅 인자로 넘겨줌 * refactor: UI 컴포넌트에 토스트 띄우는 함수만 남기고 훅으로 이동 * chore: todo 주석 삭제 * feat: 사용성 개선 - Title component 변경 및 UX writing 수정 (#352) * fix: Text component 줄바꿈 가능하도록 변경 * fix: Title component 변경 * chore: v0.1.72 배포 * feat: ux writing 변경 * fix: 디자인시스템 버전 변경 * feat: 비밀번호 입력 페이지 커스텀 훅으로 분리 (#354) * refactor: 비밀번호 설정 커스텀 훅으로 분리 * refactor: event name 상태 제거 * style: index.ts에 setEventPasswordPage 컴포넌트 추가 * refactor: navigate 책임을 UI 컴포넌트로 위임 * style: 비밀번호 입력을 관리하는 함수라는 의미로 변경 * fix: 탭 클릭 시 전체가 클릭되는 것처럼 보이는 현상 해결 (#356) * feat: 사용성 개선 - 지출 내역 입력 아이템 구현 (#357) * feat: EditableItem Component 구현 * chore: v0.1.73 배포 * style: lint 적용 * style: 오타 수정 * fix: EditableItem을 export 하지 않던 오류 수정 * chore: v0.1.74 배포 --------- Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> * refactor: 행사 생성 완료 페이지에서 불필요한 상태 제거 (#350) * refactor: 행사생성 완료페이지 불필요한 상태 제거 * refactor: 사용하지 않는 import 구문 제거 및 코드 제거 * fix: 인원 탈주 시 검색이 되지 않는 버그 해결 (#368) * fix: 머지하면서 신경쓰지 못한 코드오류 해결 (#381) * feat: Input 검증 에러 메시지 타입 구조 변경 (#376) * refactor: errorMessage 타입을 string | undefined에서 string | null로 변경 * refactor: 에러가 아닐 때 errorMessage를 null로 리턴 * fix: 에러 import 되지 않던 현상 해결 * refactor: 에러 메시지 validate 함수 리턴하는 대로 그대로 set * feat: 에러메시지 보여지도록 추가 * refactor: 에러메시지 타입 string | null로 변경 * feat: 공통 input 코드를 useInput hook으로 분리 (#379) * feat: 반복적으로 사용하는 Input 코드를 useInput 훅으로 분리 * refactor: errorMessage 상수화 * fix: useInput 분리에 따라 발생한 useSearchInMemberList 에러 해결 * feat: input에 빈문자열이 들어온다면 canSubmit을 false로 invalid한 입력값은 지우고 canSubmit은 true로 변경 * refactor: Input이 하나 인 곳에서 index를 입력하지 않아도 작동되도록 수정 * test: 훅에 필요한 테스트 추가 (#358) * refactor: useAuth에서 return하는 함수들의 이름에 하는 일의 의미를 담도록 수정 * chore: 테스트를 위한 라이브러리 설치 * chore: jest사용을 위한 환경 세팅 * chore: 테스트가 있으므로 폴더 내부로 파일 이동 * test: 이벤트 아이디를 반환하는 훅인 useEventId 테스트 로직 작성 * chore: jest 환경 세팅 파일도 컴파일 할 수 있도록 tsconfig include에 추가 * test: 토큰과 로그인을 위한 useAuth 훅 테스트 작성 * chore: polyfills와 path alias세팅 추가 * chore: useFetch를 apis에서 hooks로 이동 * feat: 새로 추가된 에러 코드에 대한 메세지 추가 * chore: 파일 이동에 따른 수정 * feat: useAuth훅이 eventId를 스스로 호출하도록 함 * refactor: 객체를 쿼리스트링으로 바꾸는 함수를 분리 * chore: 불필요한 콘솔로그 제거 * test: 모든 테스트 사전에 실행되어야 하는 모킹 수행 * chore: 불필요한 콘솔로그 제거 * test: auth 도메인의 msw 모킹 함수 구현 * chore: jsdom환경에서 실행할 msw server 세팅 * refactor: withEventId 타입을 사용하도록 수정 * test: 이벤트를 생성하기 위한 useEvent 훅을 위한 테스트 코드 작성 * test: api 요청과 에러 상태 조작을 위한 useFetch 훅의 테스트 코드 작성 * chore: useFetch 파일 이동으로 인한 수정 * chore: 파일 이동 * refactor: captureError 함수를 useFetch로부터 분리 * test: 이벤트 도메인을 위한 msw 모킹 함수 구현 * chore: 불필요한 폴더는 커버리지 분석에 포함되지 않도록 함 * chore: jsdom 테스트를 위한 라이브러리 설치 * feat: 환경변수에 저장된 서버 도메인이 없는 경우 빈 문자열을 사용하도록 수정 * feat: useError가 error도 return하도록 수정 * chore: test 명령어 추가 * test: 멤버 목록을 위한 모킹 함수 작성 * test: 멤버를 지우는 useDeleteMemberAction의 테스트 코드 작성 * test: 로그를 위한 useStepList 훅의 테스트 코드 작성 * test: 정산 현황 조회에서 이름 검색 결과를 위한 useSearchMemberReportList 훅의 테스트 코드 작성 * chore: test환경에서의 location과 pathname 세팅 * chore: tsconfig에 jest 추가 * chore: 콘솔로그 제거 * fix: 바뀐 endpoint로 변경 * chore: 위치 변경으로 인한 수정 * chore: 위치 변경으로 인한 수정 * chore: 경로 모킹 로직을 setup으로 위임 * chore: 사용하지 않는 파일 제거 * chore: lint 적용 * chore: useFetch를 위해 핸들링 되는, 되지 않는 에러를 뱉는 모킹 함수 구현 * test: stepList와 관련된 api 모킹 함수 구현 * test: 정산 내역과 관련된 api 모킹 함수 구현 * chore: lint 적용 * test: test에 사용하는 상수 선언 * chore: stepListHandler에 합쳐진 모킹 함수 파일 제거 * test: 정상인 경우를 먼저 판단하도록 조건문 순서 변경 * test: 정산 내역 목데이터 선언 * test: 멤버 목록 목데이터 선언 * test: 프로젝트에서 사용되는 도메인의 모킹 핸들러를 export * test: 지출 내역을 위한 useStepList 훅의 테스트 코드 작성 * chore: 테스트를 위한 라이브러리 설치 * chore: CI과정에서 test를 진행하도록 명령어 추가 * test: provider안에서 호출되지 않으면 에러를 뱉는 로직의 테스트 코드 작성 * chore: 불필요한 파일이 coverage 에 뜨지 않도록 추가 * test: useDeleteMemberAction 훅의 삭제 요청에서 오류가 발생했을 경우 삭제할 멤버 목록을 원래대로 돌려놓는 지 확인하는 테스트 코드 작성 * test: Error, FetchError 인 경우에 대해 올바르게 에러를 핸들링하는지 테스트 코드 작성 * test: 에러를 발생시키기 위해 음수 actionId가 들어온 경우 에러 반환 * feat: 불필요한 alert문 제거 * chore: toEqual -> toStrictEqual로 변경 * chore: 린트 적용 * fix: endpoint를 잘못 기재한 부분 수정 * chore: 파일이동에 따른 경로 수정 * chore: 린트 적용 * chore: 파일이동에 따른 경로 수정 * feat: 비밀번호 길이인 4를 상수화해 사용하도록 수정 * test: 요청 성공시 어떤 값을 반환하는지 구체적으로 테스트 이름에 명시 * chore: 린트 적용 * test: 토큰의 다양한 에러 타입에 대해 테스트하기 위한 상수 선언 * test: 토큰 내용에 따라 forbidden, expired 에러를 뱉도록 분기 추가 * test: 토큰이 forbidden, expired 일 경우 에러를 반환하는지 테스트 코드 작성 * chore: 디자인 시스템 라이브러리 업데이트 * feat: production에서만 sentry 에 로그를 보내도록 함 * chore: 린트 적용 * chore: 999라는 오류가 발생하는 멤버를 포함하는 stepList 목데이터 작성 * chore: 외부에서 사용하지 않는 함수 return에서 제거 * test: memberActionList를 typeNarrowing으로 정제하여 사용하도록 수정 * test: 삭제 요청에서 오류가 발생하는 경우를 테스트하기 위해 오류 데이터가 포함된 stepList 목데이터를 사용하도록 수정 * test: stepList 데이터가 채워진 후 테스트를 진행하도록 waitFor 추가 * test: 에러 시연을 위해 actionId가 999인 경우 에러 응답을 반환하도록 변경 * chore: 불필요한 주석 제거 * chore: 린트 적용 * chore: import 경로 수정 * refactor: 멤버 액션 삭제 훅 리팩토링 (#383) * refactor: alive -> delete member list로 변경 * refactor: 비동기 아닌 함수 async await 제거 * fix: 훅 내에서 errorIndexList 사용하고 있지 않아서 제거했습니다. * refactor: 이벤트 생성 페이지 리팩토링 (#385) * refactor: event name 관련 커스텀 훅 분리 * style: 필요하지 않은 children 제거 * feat: navigate replace true 조건으로 입력 중 상태로 되돌아갈 수 없도록 설정 * fix: 비밀번호 입력 창에서는 뒤로가기 할 때 이름으로 가도록 설정 * test: useError, useToast 테스트코드 작성 (#387) * style: errorBody -> errorInfo로 이름 변경 * test: jest에서 svg파일을 못읽으므로 이를 모킹해 오류가 발생하지 않도록 대처 * chore: coverage에서 errorProvider가 보이도록 ignore에서 제거 * feat: 불필요하게 낭비되는 상태인 hasError를 제거하고 errorMessage는 클라이언트에서 보여지는 에러메세지이므로 clientErrorMessage로 이름 수정 * refactor: ErrorProvider에서 useError를 파일로 분리 * test: 전역 에러 상태를 위한 useError 훅의 테스트 코드 작성 * chore: 파일 위치 변경으로 인한 import 경로 수정 * chore: toBeInTheDocument 를 사용하기 위한 라이브러리 import * chore: toBeInTheDocument 를 사용하기 위한 라이브러리 설치 * chore: Property 'toBeInTheDocument' does not exist on type 'JestMatchers' 에러를 발생시키지 않기 위한 타입 추가 * refactor: ToastProvider에서 useToast분리 * test: 핸들링 가능한 에러발생 시 토스트를 띄우고, 핸들링 불가능한 에러 발생 시 토스트를 띄우지 않는지 테스트 코드 작성 * feat: Toast 컴포넌트에 토스트 엘리먼트 식별을 위한 id='toast' 추가 * chore: 파일을 hooks내부로 이동 * chore: 파일 이동으로 인한 import 경로 수정 * chore: components폴더 내부는 커버리지에 포함되지 않도록 ignore에 추가 * feat: Zustand, react-query 도입 및 적용 (#388) * chore: react-query, zustand 설치 및 환경설정 * feat: react-query hook 생성 * remove: 사용하지 않는 코드 삭제 * feat: StepList 리팩토링을 위한 코드 * fix: 객체로 묶여있지 않던 prop 변경 * refactor: react-query 적용 * refactor: SetEventNamePage, SetEventPasswordPage 비즈니스 로직 hook으로 분리 * fix: CompleteCreateEventPage 변경 * refactor: react-query 적용 * feat: StepList 구조 변경을 위한 store 생성 * feat: 총 지출금액을 계산하기 위한 store 구현 * style: lint 적용 * fix: eventName을 EventPageLayout에서 받도록 변경 * style: lint 적용 * fix: 빠진 쿼리키 수정 * fix: merge 이후 수정이 필요한 부분 해결 * remove: 사용하지 않는 useStepList 파일 제거 * fix: react-query 사용으로 테스트 코드에 QueryClientProvider 감싸주는 작업 진행 * chore: store 디렉토리 추가로 jest config에 반영 * refactor: 파생상태를 활용해서 state 제거 * style: 사용하지 않는 import 문 제거 * style: 사용하지 않는 import문 제거 * chore: replace:true 추가 * remove: 사용하지 않는 파일 제거 * chore: 변경된 이름 반영 * chore: useRequest- 파일을 hooks/queries 폴더로 이동 * chore: lint 적용 * fix: jest 설정. merge 시 누락된 코드 재적용 --------- Co-authored-by: 김진호 Co-authored-by: Soyeon Choe * fix: valideMemberName의 조건문 name은 1 이하일 수 없다를 제거 (#396) Co-authored-by: Soyeon Choe * feat: 총액 업데이트 로직을 store안으로 이동 (#401) * feat: 총액 계산 로직을 store에게 위임 * chore: 사용하지 않는 import 제거 * fix: action log가 길어질 때 heigth 잘리는 버그 수정 (#408) * feat: 전체 인원 수정 '삭제' api 로직 롤백 수정 (#409) * fix: merge를 진행하며 삭제된 수정 완료시 삭제 api 요청 로직으로 수정 * fix: 삭제 버튼 클릭 후 이름을 수정하면 index 불일치로 발생하는 버그 해결 * chore: 사용하지 않는 console.log 삭제 * feat: EditableItem.Input이 동적인 width를 갖도록 수정 (#411) * feat: backGroundColor를 옵셔널로 설정할 수 있도록 수정 * feat: prefix, suffix라벨 ui구현 * style: label의 css 작성 * test: 라벨이 있는 EditableItem, 라벨이 여러개 있는 EditableItem, 리스트 형태의 EditableItem의 스토리북 작성 * chore: 필요없어진 주석 제거 * chore: v0.1.75 publish * feat: theme 인자가 필요한 타입을 위한 WithTheme 타입 작성 * feat: 실제 컴포넌트를 렌더링하고 보여지는 width를 가져오는 함수 구현 * feat: 동적으로 input의 width가 변하도록 가상 컴포넌트인 shadowRef를 추가하여 구현 * design: 동적으로 width가 변하는 input을 위한 css작성 * feat: value가 없으면 동적으로 길이를 계산할 수 없으므로 반드시 받도록하고, 변동 여부와 읽기 전용 여부를 인자로 받도록 함 * test: value를 반드시 넘겨주도록 스토리북 수정 * feat: 불필요한 삼항연산문 제거 * test: 배열 EditableItem을 테스트하는데 지장이 없도록 세터 상세하게 구현 * chore: 사용하지 않는 스타일 제거 * refactor: 길이를 직접 할당해 불필요해진 상태와 함수 제거 * refactor: 불필요하게 배열에 담아 css 프롭을 넘겨주던 부분을 제거 * feat: 기존에 사용하던 hasFocus방식과 useImperativeHandle을 돌려놓음 * feat: width를 style로 넘기는 방식이 한 틱 늦게 반영되므로 제거 * chore: 사용하지 않는 타입 제거 * feat: disabled 속성 제거 * feat: autoFocus 속성 제거 * chore: v0.1.76 배포 --------- Co-authored-by: 이태훈 * feat: 차등 정산 기능 구현 및 테스트 작성 (#406) * feat: 고정 가격을 설정했는지에 대한 isFixed 타입 추가 * feat: 지출 상세 조회, 수정 api 함수 작성 * feat: Get, Put query, mutation 작성 * feat: 고정값으로 수정할 때, 나머지 인원의 가격이 계산되는 기능 추가 * fix: isFixed field 추가로 반영되지 못한 테스트 수정 * test: useMemberReportListInAction 훅 텟트 작성 아직 엣지케이스는 작성하지 못 함;; * fix: put body 형식 수정 * test: submit 함수 테스트 코드 작성 * feat: 모든 인원의 가격을 고정시키려 했을 때 반영하지 않는 기능 * test: 모든 인원을 담을 때 테스트 작성 * fix: invalidate queries querykey actionId 명시 * fix: 중복 인원이 들어왔을 때 잘못 계산되던 문제 해결 * test: 중복 인원일 때 테스트 코드 작성 * refactor: 지출상세 훅 리팩터링 * test: 같은 멤버 다른 가격으로 변환 시 다시 계산되는 테스트 작성 * fix: isFixed 추가로 발생한 테스트 오류 수정 * feat: 각 멤버 별 isFixed 추가 반영 * refactor: 서버의 isFixed 관리로 불필요한 상태 제거 * test: isFixed 필드 추가 테스트 반영 * feat: 계산값으로 값을 변경했을 때 isFixed를 해제하는 기능구현 * test: isFixed 해제 관련 테스트 작성 * feat: member report validation 로직 작성 * chore: 테스트를 위한 코드 작성 추후 삭제 * chore: 테스트용 라우팅 삭제 * feat: 총 금액보다 큰지 검증하는 기능 추가 * feat: 차등 적용 input으로 handle하는 기능 추가 * remove: 사용하지 않는 파일 제거 * feat: 차등 적용 적용 중 지원되지 않는 기능 수정 (#423) * fix: 0원을 허용하도록 수정 * feat: 총 금액이 변동됐을 때 재계산을 실행하는 기능 추가 * feat: 하나라도 조정값이 있는지를 판단하는 기능 추가 * test: 조정된 값이 있는지 여부를 주는 기능 test 작성 * feat: 조정되지 않은 인원이 1명일 때, input을 막아버리는 기능 추가 * feat: 서버상태와 클라이언트 상태 가격이 전부 동일하면 can submit false 기능 추가 * fix: 차등 적용 can submit이 valid 하지만 false되는 버그 (#428) * fix: 0원을 허용하도록 수정 * feat: 총 금액이 변동됐을 때 재계산을 실행하는 기능 추가 * feat: 하나라도 조정값이 있는지를 판단하는 기능 추가 * test: 조정된 값이 있는지 여부를 주는 기능 test 작성 * feat: 조정되지 않은 인원이 1명일 때, input을 막아버리는 기능 추가 * feat: 서버상태와 클라이언트 상태 가격이 전부 동일하면 can submit false 기능 추가 * fix: input list가 변했을 때 can submit이 돌도록 변경 * fix: 데이터가 없을 때 초기화 되어버리는 현상 해결 * feat: 지출 내역 추가 변경사항 적용 (#414) * design: 지출 추가, 인원 추가 button 퍼블리싱 * feat: 변경된 Button에 BottomSheet onClick연결 * chore: 디자인시스템 버전 업데이트 * feat: step.type이 Bill이 아니더라도 isAddEditableItem가 true라면 BillStepItem을 렌더링하여 지출 내역 추가 Input을 띄우기 * feat: onChange에 billInput 변경하기 및 blur시 조건을 충족할 경우 서버로 api 요청 보내기 * feat: 지출 내역 post api를 요청하면 지출 내역 Input을 닫기 * feat: 디자인시스템과의 병합을 위해 Input에 value 추가 * chore: 불필요한 주석 제거 * fix: 불필요한 조건문 제거 * chore: 불필요한 console.log 삭제 * feat: 마지막 BillItem에만 EditableItem.Input을 렌더링하기 * design: 관리 페이지 디자인 수정 * fix: billInput 값을 초기화 * feat: BillItem이 존재하지 않을 때, 새로운 BillItem을 생성하여 지출 input 만들기 * feat: member action 추가후, 빈 stepList가 생성되지 않는 에러 해결 * chore: 디자인시스템 업데이트 --------- Co-authored-by: 이태훈 * feat: 지출 내역 아이템 클릭시 뜨는 차등 정산 모달 퍼블리싱 (#431) * refactor: IsFixedIcon이 재사용되기 시작했으므로 컴포넌트로 분리 * feat: DragHandleItem에 IsFixed 속성을 추가하고 IsFixedIcon 가 보여지도록 함 * test: isFixed가 있는 DragHandleItem의 스토리 추가 * chore: 불필요한 import 제거 * chore: 디자인시스템 라이브러리 업데이트 * feat: 변경된 시안에 맞게 ui 수정 * feat: 차등 정산이 적용되었을 때 제출 버튼을 활성화하는 로직을 추가 * feat: 마지막으로 차등 정산을 적용하려는 참여자는 readOnly로 수정을 막도록 함 * feat: 지출 내역 아이템에 수정 여부를 표시하기 * fix: 유효길이를 초과해 입력하려는 경우 값은 이전의 유효값으로 고정이지만 canSubmit이 false라 요청이 불가능한 오류를 수정 * feat: BottomSheet 지출 부분 삭제 & input autoFocus (#433) * chore: webpack, react, typescript 환경 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 * chore: eslint, prettier 설정 Co-authored-by: JinHo Kim Co-authored-by: Pakxe * docs: pr 템플릿 및 issue 템플릿 세팅 Co-authored-by: pakxe , soi-ha , jinhokim98 * docs: issue 템플릿에 타이틀과 관련된 부가 정보 추가 Co-authored-by: pakxe , soi-ha , jinhokim98 * chore: 모든 install 에 legacy-peer-deps를 사용하도록 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: emotion css props 사용 예제 작성 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: webpack, @emotion/react 라이브러리 설치 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: css props를 사용하기 위해 'jsxImportSource' 옵션 설정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: css props 사용 위해 모든 파일 최상단에 주석을 자동으로 작성해주도록 플러그인 세팅 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: 개발서버 포트번호 3001 -> 3000 으로 수정 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: prettier에서 useTabs를 사용하지 않도록 제거 Co-authored-by: pakxe , soi-ha , jinhokim98 , Todari * chore: 여러 명이 co-authored-by로 들어갈 수 있는지 테스트 커밋 Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari * chore: 임시로 지웠던 types 옵션을 다시 활성화 Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: jinhokim98 Co-authored-by: Todari * chore: 기본 webpack 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: theme, token 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: storybook 설정 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Button 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * feat: Text 구현 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * fix: webpack 설정 entry 파일 확장자 tsx에서 ts로 변경 Co-Authored-By: TaehunLee <85233397+Todari@users.noreply.github.com> * chore: modify-source-webpack-plugin 의존성 반영되지 않은 것 추가 Co-authored-by: pakxe * chore: css파일을 처리하기 위한 webpack 세팅 Co-author… --------- Co-authored-by: 이태훈 Co-authored-by: pakxe , soi-ha , jinhokim98 Co-authored-by: JinHo Kim Co-authored-by: Pakxe Co-authored-by: pakxe Co-authored-by: soi-ha Co-authored-by: TaehunLee <85233397+Todari@users.noreply.github.com> Co-authored-by: Soyeon Choe Co-authored-by: Arachne <66822642+Arachneee@users.noreply.github.com> Co-authored-by: Arachneee Co-authored-by: juha Co-authored-by: Juhwan Kim <13selfesteem91@naver.com> Co-authored-by: JUHA <84626225+khabh@users.noreply.github.com> Co-authored-by: Soyeon Choe <77609591+soi-ha@users.noreply.github.com> Co-authored-by: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Co-authored-by: Pakxe <64801796+pakxe@users.noreply.github.com> Co-authored-by: JUHA Co-authored-by: Arachne --- .github/workflows/backend-dev.yml | 72 + .github/workflows/backend-prod.yml | 74 + .github/workflows/backend-pull-request.yml | 44 + .github/workflows/design-pull-request.yml | 54 + .github/workflows/frontend-pull-request.yml | 49 + .github/workflows/pr-issue-close.yml | 33 + .gitmodules | 4 + HDesign/.gitignore | 12 + HDesign/.npmignore | 7 + HDesign/.npmrc | 2 + HDesign/.prettierrc | 12 + HDesign/.storybook/main.ts | 47 + HDesign/.storybook/preview.tsx | 41 + HDesign/eslint.config.mjs | 153 + HDesign/package-lock.json | 13707 +++++++++++ HDesign/package.json | 72 + HDesign/src/assets/buljusa.svg | 4 + HDesign/src/assets/confirm.svg | 10 + HDesign/src/assets/error.svg | 10 + HDesign/src/assets/index.ts | 7 + HDesign/src/assets/inputDelete.svg | 10 + HDesign/src/assets/loadingAnimation.json | 1176 + HDesign/src/assets/rightChevron.svg | 3 + HDesign/src/assets/search.svg | 3 + HDesign/src/assets/svg.d.ts | 6 + HDesign/src/assets/trash.svg | 3 + .../BottomSheet/BottomSheet.stories.tsx | 33 + .../BottomSheet/BottomSheet.style.ts | 60 + .../components/BottomSheet/BottomSheet.tsx | 55 + .../BottomSheet/BottomSheet.type.ts | 17 + .../components/BottomSheet/useBottomSheet.ts | 87 + .../src/components/Button/Button.stories.tsx | 40 + HDesign/src/components/Button/Button.style.ts | 113 + HDesign/src/components/Button/Button.tsx | 47 + HDesign/src/components/Button/Button.type.ts | 16 + .../DragHandleItem/DragHandleItem.stories.tsx | 51 + .../DragHandleItem/DragHandleItem.style.ts | 20 + .../DragHandleItem/DragHandleItem.tsx | 44 + .../DragHandleItem/DragHandleItem.type.ts | 19 + .../DragHandleItemContainer.stories.tsx | 90 + .../DragHandleItemContainer.style.ts | 34 + .../DragHandleItemContainer.tsx | 47 + .../DragHandleItemContainer.type.ts | 20 + .../EditableItem/EditableItem.Input.style.ts | 84 + .../EditableItem/EditableItem.Input.tsx | 54 + .../EditableItem/EditableItem.Input.type.ts | 22 + .../EditableItem/EditableItem.context.tsx | 23 + .../EditableItem.input.stories.tsx | 45 + .../EditableItem/EditableItem.stories.tsx | 276 + .../EditableItem/EditableItem.style.ts | 21 + .../components/EditableItem/EditableItem.tsx | 54 + .../EditableItem/EditableItem.type.ts | 22 + .../EditableItem/useEditableItem.ts | 23 + .../EditableItem/useEditableItemInput.ts | 46 + .../ExpenseList/ExpenseList.stories.tsx | 29 + .../ExpenseList/ExpenseList.style.ts | 29 + .../components/ExpenseList/ExpenseList.tsx | 37 + .../ExpenseList/ExpenseList.type.ts | 10 + .../FixedButton/FixedButton.stories.tsx | 46 + .../FixedButton/FixedButton.style.ts | 127 + .../components/FixedButton/FixedButton.tsx | 48 + .../FixedButton/FixedButton.type.ts | 16 + HDesign/src/components/Flex/Flex.style.ts | 49 + HDesign/src/components/Flex/Flex.tsx | 17 + HDesign/src/components/Flex/Flex.type.ts | 20 + HDesign/src/components/Icon/Icon.stories.tsx | 28 + HDesign/src/components/Icon/Icon.style.ts | 38 + HDesign/src/components/Icon/Icon.tsx | 29 + HDesign/src/components/Icon/Icon.type.ts | 21 + .../IconButton/IconButton.stories.tsx | 51 + .../components/IconButton/IconButton.style.ts | 102 + .../src/components/IconButton/IconButton.tsx | 22 + .../components/IconButton/IconButton.type.ts | 19 + .../src/components/Input/Input.stories.tsx | 56 + HDesign/src/components/Input/Input.style.ts | 56 + HDesign/src/components/Input/Input.tsx | 51 + HDesign/src/components/Input/Input.type.ts | 16 + HDesign/src/components/Input/useInput.ts | 71 + .../IsFixedIcon/IsFixedIcon.style.ts | 9 + .../components/IsFixedIcon/IsFixedIcon.tsx | 13 + .../components/LabelGroupInput/Element.tsx | 63 + .../LabelGroupInput/Element.type.ts | 10 + .../LabelGroupInput/GroupInputContext.tsx | 32 + .../LabelGroupInput.stories.tsx | 75 + .../LabelGroupInput/LabelGroupInput.style.ts | 25 + .../LabelGroupInput/LabelGroupInput.tsx | 48 + .../LabelGroupInput/LabelGroupInput.type.ts | 10 + .../src/components/LabelGroupInput/index.ts | 3 + .../LabelInput/LabelInput.stories.tsx | 56 + .../components/LabelInput/LabelInput.style.ts | 25 + .../src/components/LabelInput/LabelInput.tsx | 45 + .../components/LabelInput/LabelInput.type.ts | 12 + .../components/LabelInput/useLabelInput.ts | 26 + .../ListButton/ListButton.stories.tsx | 32 + .../components/ListButton/ListButton.style.ts | 16 + .../src/components/ListButton/ListButton.tsx | 36 + .../components/ListButton/ListButton.type.ts | 10 + .../src/components/Search/Search.stories.tsx | 32 + HDesign/src/components/Search/Search.style.ts | 42 + HDesign/src/components/Search/Search.tsx | 37 + .../src/components/Switch/Switch.stories.tsx | 35 + HDesign/src/components/Switch/Switch.style.ts | 6 + HDesign/src/components/Switch/Switch.tsx | 24 + HDesign/src/components/Switch/Switch.type.ts | 5 + HDesign/src/components/Tabs/Tab.tsx | 8 + HDesign/src/components/Tabs/Tab.type.ts | 16 + HDesign/src/components/Tabs/Tabs.stories.tsx | 31 + HDesign/src/components/Tabs/Tabs.style.ts | 53 + HDesign/src/components/Tabs/Tabs.tsx | 53 + HDesign/src/components/Text/Text.stories.tsx | 40 + HDesign/src/components/Text/Text.style.ts | 29 + HDesign/src/components/Text/Text.tsx | 19 + HDesign/src/components/Text/Text.type.ts | 30 + .../TextButton/TextButton.stories.tsx | 50 + .../components/TextButton/TextButton.style.ts | 10 + .../src/components/TextButton/TextButton.tsx | 25 + .../components/TextButton/TextButton.type.ts | 15 + .../src/components/Title/Title.stories.tsx | 38 + HDesign/src/components/Title/Title.style.ts | 19 + HDesign/src/components/Title/Title.tsx | 34 + HDesign/src/components/Title/Title.type.ts | 11 + .../src/components/Toast/Toast.stories.tsx | 71 + HDesign/src/components/Toast/Toast.style.ts | 44 + HDesign/src/components/Toast/Toast.tsx | 73 + HDesign/src/components/Toast/Toast.type.ts | 21 + .../Toast/ToastProvider.stories.tsx | 46 + .../src/components/Toast/ToastProvider.tsx | 59 + HDesign/src/components/TopNav/Back.tsx | 17 + .../src/components/TopNav/TopNav.stories.tsx | 50 + HDesign/src/components/TopNav/TopNav.style.ts | 18 + HDesign/src/components/TopNav/TopNav.tsx | 20 + HDesign/src/index.tsx | 62 + HDesign/src/layouts/ContentLayout.tsx | 25 + HDesign/src/layouts/MainLayout.tsx | 26 + HDesign/src/theme/GlobalStyle.ts | 123 + HDesign/src/theme/HDesignProvider.tsx | 37 + HDesign/src/theme/theme.type.ts | 7 + HDesign/src/token/colors.ts | 109 + HDesign/src/token/typography.ts | 67 + HDesign/src/type/strictPropsWithChildren.ts | 3 + HDesign/src/type/withTheme.ts | 5 + .../src/utils/changeCamelCaseToKebabCase.ts | 3 + HDesign/src/utils/colors.ts | 88 + HDesign/tsconfig.json | 34 + client/.gitignore | 14 + client/.gitkeep | 0 client/.npmrc | 2 + client/.prettierrc | 12 + client/cypress.config.ts | 12 + client/cypress/constants/constants.ts | 6 + client/cypress/e2e/createEvent.cy.ts | 79 + client/cypress/fixtures/postEvent.json | 3 + client/cypress/support/commands.ts | 58 + client/cypress/support/e2e.ts | 1 + client/eslint.config.mjs | 112 + client/favicon.ico | Bin 0 -> 44932 bytes client/index.html | 33 + client/jest.config.ts | 49 + client/jest.polyfills.ts | 20 + client/jest.setup.ts | 24 + client/package-lock.json | 19037 ++++++++++++++++ client/package.json | 85 + client/public/mockServiceWorker.js | 281 + client/src/App.tsx | 31 + client/src/GlobalStyle.ts | 160 + client/src/UnhandledErrorBoundary.tsx | 10 + client/src/apis/baseUrl.ts | 3 + client/src/apis/fetcher.ts | 120 + client/src/apis/request/auth.ts | 25 + client/src/apis/request/bill.ts | 69 + client/src/apis/request/event.ts | 32 + client/src/apis/request/member.ts | 84 + client/src/apis/request/report.ts | 19 + client/src/apis/request/stepList.ts | 17 + client/src/apis/tempPrefix.ts | 2 + client/src/apis/withEventId.type.ts | 3 + client/src/assets/image/addBillMockup.svg | 312 + client/src/assets/image/addMemberMockup.svg | 317 + client/src/assets/image/chevronDownLarge.svg | 3 + client/src/assets/image/dog.svg | 49 + client/src/assets/image/heundeut.svg | 1 + .../src/assets/image/memberReportMockup.svg | 311 + client/src/assets/image/runningDog.svg | 9 + client/src/assets/image/standingDog.svg | 9 + .../AppErrorBoundary/ErrorCatcher.test.tsx | 92 + .../AppErrorBoundary/ErrorCatcher.tsx | 62 + .../src/components/Common/Logo/Logo.style.ts | 8 + .../components/Common/Logo/RunningDogLogo.tsx | 13 + .../Common/Logo/StandingDogLogo.tsx | 13 + client/src/components/Common/Logo/index.ts | 2 + .../MemberReportList/MemberReportList.tsx | 22 + .../ExpenseDetailModal/ExpenseDetailModal.tsx | 142 + .../MemberListInBillStep.style.ts | 10 + .../MemberListInBillStep.tsx | 53 + .../Modal/MemberListInBillStep/index.ts | 1 + .../ModalBasedOnMemberCount.tsx | 39 + .../AddMemberActionListModalContent.style.ts | 23 + .../AddMemberActionListModalContent.tsx | 50 + .../InMember.tsx | 35 + .../OutMember.tsx | 52 + .../AddMemberActionListModalContent/index.ts | 1 + .../DeleteMemberActionModal.style.ts | 27 + .../DeleteMemberActionModal.tsx | 88 + .../DeleteMemberActionModal/index.ts | 1 + .../PutAndDeleteBillActionModal.tsx | 149 + .../PutAndDeltetBillActionModal.style.ts | 28 + .../PutAndDeleteBillActionModal/index.ts | 1 + .../SetActionListModal.style.ts | 20 + .../SetActionModal/SetActionListModal.tsx | 42 + .../components/Modal/SetActionModal/index.ts | 1 + .../SetAllMemberListModal.style.ts | 36 + .../SetAllMemberListModal.tsx | 80 + .../SetInitialMemberListModal.style.ts | 20 + .../SetInitialMemberListModal.tsx | 66 + .../Modal/SetInitialMemberListModal/index.ts | 1 + client/src/components/Modal/index.ts | 4 + .../QueryClientBoundary.tsx | 24 + .../src/components/StepList/BillStepItem.tsx | 138 + .../components/StepList/MemberStepItem.tsx | 38 + client/src/components/StepList/Step.tsx | 51 + client/src/components/StepList/StepList.tsx | 76 + client/src/components/Toast/Toast.style.ts | 65 + client/src/components/Toast/Toast.tsx | 75 + client/src/components/Toast/Toast.type.ts | 22 + client/src/constants/errorMessage.ts | 49 + client/src/constants/password.ts | 1 + client/src/constants/queryKeys.ts | 10 + client/src/constants/regExp.ts | 8 + client/src/constants/routerUrls.ts | 10 + client/src/constants/rule.ts | 8 + client/src/errors/FetchError.ts | 23 + client/src/global.d.ts | 11 + .../queries/useRequestDeleteAllMemberList.ts | 28 + .../queries/useRequestDeleteBillAction.ts | 26 + .../queries/useRequestDeleteMemberAction.ts | 28 + .../queries/useRequestGetAllMemberList.ts | 18 + .../useRequestGetCurrentInMemberList.ts | 18 + .../hooks/queries/useRequestGetEventName.ts | 18 + .../queries/useRequestGetMemberReportList.ts | 17 + .../useRequestGetMemberReportListInAction.ts | 24 + .../hooks/queries/useRequestGetStepList.ts | 30 + .../queries/useRequestPostAuthentication.ts | 23 + .../hooks/queries/useRequestPostBillList.ts | 27 + .../src/hooks/queries/useRequestPostEvent.ts | 16 + .../src/hooks/queries/useRequestPostLogin.ts | 26 + .../hooks/queries/useRequestPostMemberList.ts | 37 + .../queries/useRequestPutAllMemberList.ts | 28 + .../hooks/queries/useRequestPutBillAction.ts | 29 + .../useRequestPutMemberReportListInAction.ts | 49 + .../useDeleteMemberAction.test.tsx | 139 + .../useDeleteMemberAction.tsx | 86 + client/src/hooks/useDynamicInput.tsx | 142 + client/src/hooks/useEventLogin.ts | 42 + client/src/hooks/useInput.tsx | 97 + .../useMemberReportInput.tsx | 89 + .../useMemberReportListInAction.test.tsx | 327 + .../useMemberReportListInAction.ts | 156 + client/src/hooks/useNavSwitch.tsx | 42 + client/src/hooks/usePutAndDeleteBillAction.ts | 113 + client/src/hooks/useSearchInMemberList.ts | 54 + .../useSearchMemberReportList.test.tsx | 41 + .../useSearchMemberReportList.tsx | 16 + client/src/hooks/useSetAllMemberList.tsx | 100 + client/src/hooks/useSetBillInput.ts | 67 + client/src/hooks/useSetEventNamePage.ts | 32 + client/src/hooks/useSetEventPasswordPage.ts | 60 + client/src/hooks/useToast/ToastProvider.tsx | 47 + client/src/hooks/useToast/useToast.test.tsx | 80 + client/src/hooks/useToast/useToast.tsx | 13 + client/src/index.tsx | 32 + client/src/mocks/browser.ts | 5 + client/src/mocks/handlers.ts | 15 + client/src/mocks/handlers/authHandlers.ts | 104 + client/src/mocks/handlers/eventHandlers.ts | 55 + .../handlers/memberReportInActionHandlers.ts | 49 + client/src/mocks/handlers/reportHandlers.ts | 13 + client/src/mocks/handlers/stepListHandler.ts | 113 + client/src/mocks/handlers/testHandlers.ts | 23 + client/src/mocks/invalidMemberStepList.json | 100 + client/src/mocks/memberActionStepList.json | 23 + .../src/mocks/memberReportListInAction.json | 6 + client/src/mocks/memberReportSearchList.json | 10 + client/src/mocks/reportList.json | 18 + client/src/mocks/server.ts | 5 + client/src/mocks/serverConstants.ts | 4 + client/src/mocks/stepList.json | 100 + client/src/mocks/svg.ts | 2 + client/src/mocks/validValueForTest.ts | 4 + .../CompleteCreateEventPage.tsx | 29 + .../CreateEventPage/SetEventNamePage.tsx | 42 + .../CreateEventPage/SetEventPasswordPage.tsx | 41 + client/src/pages/CreateEventPage/index.ts | 3 + client/src/pages/ErrorPage/ErrorPage.tsx | 14 + .../EventPage/AdminPage/AdminPage.style.ts | 23 + .../pages/EventPage/AdminPage/AdminPage.tsx | 90 + .../EventPage/AdminPage/EventLoginPage.tsx | 35 + client/src/pages/EventPage/AdminPage/index.ts | 1 + .../src/pages/EventPage/EventPageLayout.tsx | 65 + .../src/pages/EventPage/HomePage/HomePage.tsx | 26 + client/src/pages/EventPage/HomePage/index.ts | 1 + client/src/pages/EventPage/index.ts | 1 + client/src/pages/MainPage/MainPage.tsx | 23 + client/src/pages/MainPage/Nav/Nav.style.ts | 22 + client/src/pages/MainPage/Nav/Nav.tsx | 27 + .../pages/MainPage/Section/AddBillSection.tsx | 31 + .../MainPage/Section/AddMemberSection.tsx | 33 + .../MainPage/Section/DescriptionSection.tsx | 33 + .../pages/MainPage/Section/MainSection.tsx | 93 + .../MainPage/Section/MemberReportSection.tsx | 31 + client/src/pages/MainPage/index.ts | 1 + client/src/router.tsx | 58 + client/src/store/appErrorStore.ts | 14 + client/src/store/stepListStore.ts | 16 + client/src/store/totalExpenseAmountStore.ts | 18 + client/src/types/fetchErrorType.ts | 11 + client/src/types/serviceType.ts | 80 + client/src/utils/caculateExpense.ts | 14 + client/src/utils/captureError.ts | 49 + client/src/utils/getEventIdByUrl.ts | 13 + .../src/utils/getEventPageUrlByEnvironment.ts | 11 + client/src/utils/groupActions.ts | 27 + client/src/utils/isArraysEqual.ts | 16 + client/src/utils/objectToQueryString.ts | 9 + client/src/utils/sendLogToSentry.ts | 66 + client/src/utils/stepListToActions.ts | 23 + client/src/utils/validate/type.ts | 5 + .../src/utils/validate/validateEventName.ts | 13 + .../utils/validate/validateEventPassword.ts | 13 + .../src/utils/validate/validateMemberName.ts | 34 + .../validate/validateMemberReportInAction.ts | 33 + client/src/utils/validate/validatePurchase.ts | 47 + client/tsconfig.json | 53 + client/webpack.common.mjs | 60 + client/webpack.dev.mjs | 33 + client/webpack.prod.mjs | 31 + server/.gitignore | 244 + server/.gitkeep | 0 server/Dockerfile | 9 + server/build.gradle | 86 + server/docs/24-08-04-erd.sql | 65 + server/docs/24-08-04-erd.svg | 4 + server/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + server/gradlew | 249 + server/gradlew.bat | 92 + server/settings.gradle | 1 + server/src/docs/asciidoc/billAction.adoc | 121 + .../src/docs/asciidoc/billActionDetail.adoc | 93 + server/src/docs/asciidoc/event.adoc | 205 + server/src/docs/asciidoc/index.adoc | 15 + server/src/docs/asciidoc/memberAction.adoc | 100 + .../src/docs/asciidoc/memberBillReport.adoc | 17 + .../haengdong/HaengdongApplication.java | 15 + .../haengdong/application/ActionService.java | 39 + .../haengdong/application/AuthService.java | 41 + .../application/BillActionDetailService.java | 76 + .../application/BillActionService.java | 80 + .../haengdong/application/EventService.java | 170 + .../application/MemberActionFactory.java | 62 + .../application/MemberActionService.java | 100 + .../request/BillActionAppRequest.java | 15 + .../BillActionDetailUpdateAppRequest.java | 8 + .../BillActionDetailsUpdateAppRequest.java | 8 + .../request/BillActionUpdateAppRequest.java | 7 + .../application/request/EventAppRequest.java | 10 + .../request/EventLoginAppRequest.java | 4 + .../request/MemberActionSaveAppRequest.java | 12 + .../request/MemberActionsSaveAppRequest.java | 6 + .../request/MemberNameUpdateAppRequest.java | 7 + .../request/MemberNamesUpdateAppRequest.java | 8 + .../response/ActionAppResponse.java | 61 + .../response/BillActionDetailAppResponse.java | 18 + .../BillActionDetailsAppResponse.java | 14 + .../response/CurrentMemberAppResponse.java | 10 + .../response/EventAppResponse.java | 10 + .../response/EventDetailAppResponse.java | 10 + .../response/MemberBillReportAppResponse.java | 4 + .../response/MembersAppResponse.java | 8 + .../haengdong/config/AdminInterceptor.java | 51 + .../config/RequestServletFilter.java | 23 + .../server/haengdong/config/WebMvcConfig.java | 66 + .../haengdong/domain/TokenProvider.java | 12 + .../haengdong/domain/action/Action.java | 42 + .../domain/action/ActionRepository.java | 23 + .../haengdong/domain/action/BillAction.java | 156 + .../domain/action/BillActionDetail.java | 61 + .../action/BillActionDetailRepository.java | 20 + .../domain/action/BillActionRepository.java | 27 + .../domain/action/CurrentMembers.java | 81 + .../haengdong/domain/action/MemberAction.java | 76 + .../domain/action/MemberActionRepository.java | 53 + .../domain/action/MemberActionStatus.java | 19 + .../domain/action/MemberBillReport.java | 75 + .../domain/action/MemberGroupIdProvider.java | 11 + .../server/haengdong/domain/event/Event.java | 70 + .../domain/event/EventRepository.java | 11 + .../haengdong/domain/event/EventStep.java | 28 + .../domain/event/EventTokenProvider.java | 12 + .../haengdong/domain/event/Password.java | 52 + .../exception/AuthenticationException.java | 19 + .../haengdong/exception/ErrorResponse.java | 15 + .../exception/GlobalExceptionHandler.java | 90 + .../exception/HaengdongErrorCode.java | 69 + .../exception/HaengdongException.java | 19 + .../auth/AuthenticationExtractor.java | 23 + .../infrastructure/auth/CookieProperties.java | 15 + .../infrastructure/auth/JwtTokenProvider.java | 54 + .../infrastructure/auth/TokenProperties.java | 7 + .../presentation/ActionController.java | 26 + .../presentation/BillActionController.java | 55 + .../BillActionDetailController.java | 42 + .../presentation/EventController.java | 120 + .../presentation/MemberActionController.java | 60 + .../BillActionDetailUpdateRequest.java | 21 + .../BillActionDetailsUpdateRequest.java | 16 + .../request/BillActionSaveRequest.java | 19 + .../request/BillActionUpdateRequest.java | 18 + .../request/BillActionsSaveRequest.java | 18 + .../request/EventLoginRequest.java | 14 + .../request/EventSaveRequest.java | 18 + .../request/MemberActionsSaveRequest.java | 25 + .../request/MemberNameUpdateRequest.java | 18 + .../request/MemberNamesUpdateRequest.java | 17 + .../presentation/response/ActionResponse.java | 26 + .../response/ActionResponse2.java | 22 + .../response/ActionsResponse.java | 14 + .../response/BillActionDetailResponse.java | 18 + .../response/BillActionDetailsResponse.java | 16 + .../response/CurrentMembersResponse.java | 15 + .../response/EventDetailResponse.java | 10 + .../presentation/response/EventResponse.java | 10 + .../response/MemberBillReportResponse.java | 10 + .../response/MemberBillReportsResponse.java | 15 + .../response/MembersResponse.java | 13 + .../presentation/response/StepResponse.java | 27 + .../presentation/response/StepsResponse.java | 56 + server/src/main/resources/application.yml | 66 + server/src/main/resources/config | 1 + server/src/main/resources/logback-spring.xml | 97 + .../application/ActionServiceTest.java | 91 + .../BillActionDetailServiceTest.java | 111 + .../application/BillActionServiceTest.java | 229 + .../application/EventServiceTest.java | 231 + .../application/MemberActionFactoryTest.java | 223 + .../application/MemberActionServiceTest.java | 251 + .../application/ServiceTestSupport.java | 11 + .../docs/ActionControllerDocsTest.java | 70 + .../docs/BillActionControllerDocsTest.java | 128 + .../BillActionDetailControllerDocsTest.java | 127 + .../docs/EventControllerDocsTest.java | 381 + .../docs/MemberActionControllerDocsTest.java | 157 + .../haengdong/docs/RestDocsSupport.java | 28 + .../haengdong/domain/action/ActionTest.java | 31 + .../domain/action/BillActionTest.java | 89 + .../domain/action/CurrentMembersTest.java | 97 + .../domain/action/MemberBillReportTest.java | 56 + .../haengdong/domain/event/EventTest.java | 65 + .../haengdong/domain/event/PasswordTest.java | 19 + .../presentation/ActionControllerTest.java | 36 + .../BillActionControllerTest.java | 97 + .../BillActionDetailControllerTest.java | 56 + .../presentation/ControllerTestSupport.java | 53 + .../presentation/EventControllerTest.java | 111 + .../MemberActionControllerTest.java | 74 + .../response/StepsResponseTest.java | 63 + .../support/extension/DatabaseCleaner.java | 52 + .../extension/DatabaseCleanerExtension.java | 19 + .../haengdong/support/fixture/Fixture.java | 15 + 468 files changed, 55030 insertions(+) create mode 100644 .github/workflows/backend-dev.yml create mode 100644 .github/workflows/backend-prod.yml create mode 100644 .github/workflows/backend-pull-request.yml create mode 100644 .github/workflows/design-pull-request.yml create mode 100644 .github/workflows/frontend-pull-request.yml create mode 100644 .github/workflows/pr-issue-close.yml create mode 100644 .gitmodules create mode 100644 HDesign/.gitignore create mode 100644 HDesign/.npmignore create mode 100644 HDesign/.npmrc create mode 100644 HDesign/.prettierrc create mode 100644 HDesign/.storybook/main.ts create mode 100644 HDesign/.storybook/preview.tsx create mode 100644 HDesign/eslint.config.mjs create mode 100644 HDesign/package-lock.json create mode 100644 HDesign/package.json create mode 100644 HDesign/src/assets/buljusa.svg create mode 100644 HDesign/src/assets/confirm.svg create mode 100644 HDesign/src/assets/error.svg create mode 100644 HDesign/src/assets/index.ts create mode 100644 HDesign/src/assets/inputDelete.svg create mode 100644 HDesign/src/assets/loadingAnimation.json create mode 100644 HDesign/src/assets/rightChevron.svg create mode 100644 HDesign/src/assets/search.svg create mode 100644 HDesign/src/assets/svg.d.ts create mode 100644 HDesign/src/assets/trash.svg create mode 100644 HDesign/src/components/BottomSheet/BottomSheet.stories.tsx create mode 100644 HDesign/src/components/BottomSheet/BottomSheet.style.ts create mode 100644 HDesign/src/components/BottomSheet/BottomSheet.tsx create mode 100644 HDesign/src/components/BottomSheet/BottomSheet.type.ts create mode 100644 HDesign/src/components/BottomSheet/useBottomSheet.ts create mode 100644 HDesign/src/components/Button/Button.stories.tsx create mode 100644 HDesign/src/components/Button/Button.style.ts create mode 100644 HDesign/src/components/Button/Button.tsx create mode 100644 HDesign/src/components/Button/Button.type.ts create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.style.ts create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.tsx create mode 100644 HDesign/src/components/DragHandleItem/DragHandleItem.type.ts create mode 100644 HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx create mode 100644 HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts create mode 100644 HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.tsx create mode 100644 HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.type.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.Input.style.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.Input.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.Input.type.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.context.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.input.stories.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.stories.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.style.ts create mode 100644 HDesign/src/components/EditableItem/EditableItem.tsx create mode 100644 HDesign/src/components/EditableItem/EditableItem.type.ts create mode 100644 HDesign/src/components/EditableItem/useEditableItem.ts create mode 100644 HDesign/src/components/EditableItem/useEditableItemInput.ts create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.stories.tsx create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.style.ts create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.tsx create mode 100644 HDesign/src/components/ExpenseList/ExpenseList.type.ts create mode 100644 HDesign/src/components/FixedButton/FixedButton.stories.tsx create mode 100644 HDesign/src/components/FixedButton/FixedButton.style.ts create mode 100644 HDesign/src/components/FixedButton/FixedButton.tsx create mode 100644 HDesign/src/components/FixedButton/FixedButton.type.ts create mode 100644 HDesign/src/components/Flex/Flex.style.ts create mode 100644 HDesign/src/components/Flex/Flex.tsx create mode 100644 HDesign/src/components/Flex/Flex.type.ts create mode 100644 HDesign/src/components/Icon/Icon.stories.tsx create mode 100644 HDesign/src/components/Icon/Icon.style.ts create mode 100644 HDesign/src/components/Icon/Icon.tsx create mode 100644 HDesign/src/components/Icon/Icon.type.ts create mode 100644 HDesign/src/components/IconButton/IconButton.stories.tsx create mode 100644 HDesign/src/components/IconButton/IconButton.style.ts create mode 100644 HDesign/src/components/IconButton/IconButton.tsx create mode 100644 HDesign/src/components/IconButton/IconButton.type.ts create mode 100644 HDesign/src/components/Input/Input.stories.tsx create mode 100644 HDesign/src/components/Input/Input.style.ts create mode 100644 HDesign/src/components/Input/Input.tsx create mode 100644 HDesign/src/components/Input/Input.type.ts create mode 100644 HDesign/src/components/Input/useInput.ts create mode 100644 HDesign/src/components/IsFixedIcon/IsFixedIcon.style.ts create mode 100644 HDesign/src/components/IsFixedIcon/IsFixedIcon.tsx create mode 100644 HDesign/src/components/LabelGroupInput/Element.tsx create mode 100644 HDesign/src/components/LabelGroupInput/Element.type.ts create mode 100644 HDesign/src/components/LabelGroupInput/GroupInputContext.tsx create mode 100644 HDesign/src/components/LabelGroupInput/LabelGroupInput.stories.tsx create mode 100644 HDesign/src/components/LabelGroupInput/LabelGroupInput.style.ts create mode 100644 HDesign/src/components/LabelGroupInput/LabelGroupInput.tsx create mode 100644 HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts create mode 100644 HDesign/src/components/LabelGroupInput/index.ts create mode 100644 HDesign/src/components/LabelInput/LabelInput.stories.tsx create mode 100644 HDesign/src/components/LabelInput/LabelInput.style.ts create mode 100644 HDesign/src/components/LabelInput/LabelInput.tsx create mode 100644 HDesign/src/components/LabelInput/LabelInput.type.ts create mode 100644 HDesign/src/components/LabelInput/useLabelInput.ts create mode 100644 HDesign/src/components/ListButton/ListButton.stories.tsx create mode 100644 HDesign/src/components/ListButton/ListButton.style.ts create mode 100644 HDesign/src/components/ListButton/ListButton.tsx create mode 100644 HDesign/src/components/ListButton/ListButton.type.ts create mode 100644 HDesign/src/components/Search/Search.stories.tsx create mode 100644 HDesign/src/components/Search/Search.style.ts create mode 100644 HDesign/src/components/Search/Search.tsx create mode 100644 HDesign/src/components/Switch/Switch.stories.tsx create mode 100644 HDesign/src/components/Switch/Switch.style.ts create mode 100644 HDesign/src/components/Switch/Switch.tsx create mode 100644 HDesign/src/components/Switch/Switch.type.ts create mode 100644 HDesign/src/components/Tabs/Tab.tsx create mode 100644 HDesign/src/components/Tabs/Tab.type.ts create mode 100644 HDesign/src/components/Tabs/Tabs.stories.tsx create mode 100644 HDesign/src/components/Tabs/Tabs.style.ts create mode 100644 HDesign/src/components/Tabs/Tabs.tsx create mode 100644 HDesign/src/components/Text/Text.stories.tsx create mode 100644 HDesign/src/components/Text/Text.style.ts create mode 100644 HDesign/src/components/Text/Text.tsx create mode 100644 HDesign/src/components/Text/Text.type.ts create mode 100644 HDesign/src/components/TextButton/TextButton.stories.tsx create mode 100644 HDesign/src/components/TextButton/TextButton.style.ts create mode 100644 HDesign/src/components/TextButton/TextButton.tsx create mode 100644 HDesign/src/components/TextButton/TextButton.type.ts create mode 100644 HDesign/src/components/Title/Title.stories.tsx create mode 100644 HDesign/src/components/Title/Title.style.ts create mode 100644 HDesign/src/components/Title/Title.tsx create mode 100644 HDesign/src/components/Title/Title.type.ts create mode 100644 HDesign/src/components/Toast/Toast.stories.tsx create mode 100644 HDesign/src/components/Toast/Toast.style.ts create mode 100644 HDesign/src/components/Toast/Toast.tsx create mode 100644 HDesign/src/components/Toast/Toast.type.ts create mode 100644 HDesign/src/components/Toast/ToastProvider.stories.tsx create mode 100644 HDesign/src/components/Toast/ToastProvider.tsx create mode 100644 HDesign/src/components/TopNav/Back.tsx create mode 100644 HDesign/src/components/TopNav/TopNav.stories.tsx create mode 100644 HDesign/src/components/TopNav/TopNav.style.ts create mode 100644 HDesign/src/components/TopNav/TopNav.tsx create mode 100644 HDesign/src/index.tsx create mode 100644 HDesign/src/layouts/ContentLayout.tsx create mode 100644 HDesign/src/layouts/MainLayout.tsx create mode 100644 HDesign/src/theme/GlobalStyle.ts create mode 100644 HDesign/src/theme/HDesignProvider.tsx create mode 100644 HDesign/src/theme/theme.type.ts create mode 100644 HDesign/src/token/colors.ts create mode 100644 HDesign/src/token/typography.ts create mode 100644 HDesign/src/type/strictPropsWithChildren.ts create mode 100644 HDesign/src/type/withTheme.ts create mode 100644 HDesign/src/utils/changeCamelCaseToKebabCase.ts create mode 100644 HDesign/src/utils/colors.ts create mode 100644 HDesign/tsconfig.json create mode 100644 client/.gitignore delete mode 100644 client/.gitkeep create mode 100644 client/.npmrc create mode 100644 client/.prettierrc create mode 100644 client/cypress.config.ts create mode 100644 client/cypress/constants/constants.ts create mode 100644 client/cypress/e2e/createEvent.cy.ts create mode 100644 client/cypress/fixtures/postEvent.json create mode 100644 client/cypress/support/commands.ts create mode 100644 client/cypress/support/e2e.ts create mode 100644 client/eslint.config.mjs create mode 100644 client/favicon.ico create mode 100644 client/index.html create mode 100644 client/jest.config.ts create mode 100644 client/jest.polyfills.ts create mode 100644 client/jest.setup.ts create mode 100644 client/package-lock.json create mode 100644 client/package.json create mode 100644 client/public/mockServiceWorker.js create mode 100644 client/src/App.tsx create mode 100644 client/src/GlobalStyle.ts create mode 100644 client/src/UnhandledErrorBoundary.tsx create mode 100644 client/src/apis/baseUrl.ts create mode 100644 client/src/apis/fetcher.ts create mode 100644 client/src/apis/request/auth.ts create mode 100644 client/src/apis/request/bill.ts create mode 100644 client/src/apis/request/event.ts create mode 100644 client/src/apis/request/member.ts create mode 100644 client/src/apis/request/report.ts create mode 100644 client/src/apis/request/stepList.ts create mode 100644 client/src/apis/tempPrefix.ts create mode 100644 client/src/apis/withEventId.type.ts create mode 100644 client/src/assets/image/addBillMockup.svg create mode 100644 client/src/assets/image/addMemberMockup.svg create mode 100644 client/src/assets/image/chevronDownLarge.svg create mode 100644 client/src/assets/image/dog.svg create mode 100644 client/src/assets/image/heundeut.svg create mode 100644 client/src/assets/image/memberReportMockup.svg create mode 100644 client/src/assets/image/runningDog.svg create mode 100644 client/src/assets/image/standingDog.svg create mode 100644 client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx create mode 100644 client/src/components/AppErrorBoundary/ErrorCatcher.tsx create mode 100644 client/src/components/Common/Logo/Logo.style.ts create mode 100644 client/src/components/Common/Logo/RunningDogLogo.tsx create mode 100644 client/src/components/Common/Logo/StandingDogLogo.tsx create mode 100644 client/src/components/Common/Logo/index.ts create mode 100644 client/src/components/MemberReportList/MemberReportList.tsx create mode 100644 client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx create mode 100644 client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts create mode 100644 client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx create mode 100644 client/src/components/Modal/MemberListInBillStep/index.ts create mode 100644 client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx create mode 100644 client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts create mode 100644 client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx create mode 100644 client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx create mode 100644 client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx create mode 100644 client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts create mode 100644 client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts create mode 100644 client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx create mode 100644 client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts create mode 100644 client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx create mode 100644 client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts create mode 100644 client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts create mode 100644 client/src/components/Modal/SetActionModal/SetActionListModal.style.ts create mode 100644 client/src/components/Modal/SetActionModal/SetActionListModal.tsx create mode 100644 client/src/components/Modal/SetActionModal/index.ts create mode 100644 client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts create mode 100644 client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx create mode 100644 client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts create mode 100644 client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx create mode 100644 client/src/components/Modal/SetInitialMemberListModal/index.ts create mode 100644 client/src/components/Modal/index.ts create mode 100644 client/src/components/QueryClientBoundary/QueryClientBoundary.tsx create mode 100644 client/src/components/StepList/BillStepItem.tsx create mode 100644 client/src/components/StepList/MemberStepItem.tsx create mode 100644 client/src/components/StepList/Step.tsx create mode 100644 client/src/components/StepList/StepList.tsx create mode 100644 client/src/components/Toast/Toast.style.ts create mode 100644 client/src/components/Toast/Toast.tsx create mode 100644 client/src/components/Toast/Toast.type.ts create mode 100644 client/src/constants/errorMessage.ts create mode 100644 client/src/constants/password.ts create mode 100644 client/src/constants/queryKeys.ts create mode 100644 client/src/constants/regExp.ts create mode 100644 client/src/constants/routerUrls.ts create mode 100644 client/src/constants/rule.ts create mode 100644 client/src/errors/FetchError.ts create mode 100644 client/src/global.d.ts create mode 100644 client/src/hooks/queries/useRequestDeleteAllMemberList.ts create mode 100644 client/src/hooks/queries/useRequestDeleteBillAction.ts create mode 100644 client/src/hooks/queries/useRequestDeleteMemberAction.ts create mode 100644 client/src/hooks/queries/useRequestGetAllMemberList.ts create mode 100644 client/src/hooks/queries/useRequestGetCurrentInMemberList.ts create mode 100644 client/src/hooks/queries/useRequestGetEventName.ts create mode 100644 client/src/hooks/queries/useRequestGetMemberReportList.ts create mode 100644 client/src/hooks/queries/useRequestGetMemberReportListInAction.ts create mode 100644 client/src/hooks/queries/useRequestGetStepList.ts create mode 100644 client/src/hooks/queries/useRequestPostAuthentication.ts create mode 100644 client/src/hooks/queries/useRequestPostBillList.ts create mode 100644 client/src/hooks/queries/useRequestPostEvent.ts create mode 100644 client/src/hooks/queries/useRequestPostLogin.ts create mode 100644 client/src/hooks/queries/useRequestPostMemberList.ts create mode 100644 client/src/hooks/queries/useRequestPutAllMemberList.ts create mode 100644 client/src/hooks/queries/useRequestPutBillAction.ts create mode 100644 client/src/hooks/queries/useRequestPutMemberReportListInAction.ts create mode 100644 client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx create mode 100644 client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx create mode 100644 client/src/hooks/useDynamicInput.tsx create mode 100644 client/src/hooks/useEventLogin.ts create mode 100644 client/src/hooks/useInput.tsx create mode 100644 client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx create mode 100644 client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx create mode 100644 client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts create mode 100644 client/src/hooks/useNavSwitch.tsx create mode 100644 client/src/hooks/usePutAndDeleteBillAction.ts create mode 100644 client/src/hooks/useSearchInMemberList.ts create mode 100644 client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx create mode 100644 client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx create mode 100644 client/src/hooks/useSetAllMemberList.tsx create mode 100644 client/src/hooks/useSetBillInput.ts create mode 100644 client/src/hooks/useSetEventNamePage.ts create mode 100644 client/src/hooks/useSetEventPasswordPage.ts create mode 100644 client/src/hooks/useToast/ToastProvider.tsx create mode 100644 client/src/hooks/useToast/useToast.test.tsx create mode 100644 client/src/hooks/useToast/useToast.tsx create mode 100644 client/src/index.tsx create mode 100644 client/src/mocks/browser.ts create mode 100644 client/src/mocks/handlers.ts create mode 100644 client/src/mocks/handlers/authHandlers.ts create mode 100644 client/src/mocks/handlers/eventHandlers.ts create mode 100644 client/src/mocks/handlers/memberReportInActionHandlers.ts create mode 100644 client/src/mocks/handlers/reportHandlers.ts create mode 100644 client/src/mocks/handlers/stepListHandler.ts create mode 100644 client/src/mocks/handlers/testHandlers.ts create mode 100644 client/src/mocks/invalidMemberStepList.json create mode 100644 client/src/mocks/memberActionStepList.json create mode 100644 client/src/mocks/memberReportListInAction.json create mode 100644 client/src/mocks/memberReportSearchList.json create mode 100644 client/src/mocks/reportList.json create mode 100644 client/src/mocks/server.ts create mode 100644 client/src/mocks/serverConstants.ts create mode 100644 client/src/mocks/stepList.json create mode 100644 client/src/mocks/svg.ts create mode 100644 client/src/mocks/validValueForTest.ts create mode 100644 client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx create mode 100644 client/src/pages/CreateEventPage/SetEventNamePage.tsx create mode 100644 client/src/pages/CreateEventPage/SetEventPasswordPage.tsx create mode 100644 client/src/pages/CreateEventPage/index.ts create mode 100644 client/src/pages/ErrorPage/ErrorPage.tsx create mode 100644 client/src/pages/EventPage/AdminPage/AdminPage.style.ts create mode 100644 client/src/pages/EventPage/AdminPage/AdminPage.tsx create mode 100644 client/src/pages/EventPage/AdminPage/EventLoginPage.tsx create mode 100644 client/src/pages/EventPage/AdminPage/index.ts create mode 100644 client/src/pages/EventPage/EventPageLayout.tsx create mode 100644 client/src/pages/EventPage/HomePage/HomePage.tsx create mode 100644 client/src/pages/EventPage/HomePage/index.ts create mode 100644 client/src/pages/EventPage/index.ts create mode 100644 client/src/pages/MainPage/MainPage.tsx create mode 100644 client/src/pages/MainPage/Nav/Nav.style.ts create mode 100644 client/src/pages/MainPage/Nav/Nav.tsx create mode 100644 client/src/pages/MainPage/Section/AddBillSection.tsx create mode 100644 client/src/pages/MainPage/Section/AddMemberSection.tsx create mode 100644 client/src/pages/MainPage/Section/DescriptionSection.tsx create mode 100644 client/src/pages/MainPage/Section/MainSection.tsx create mode 100644 client/src/pages/MainPage/Section/MemberReportSection.tsx create mode 100644 client/src/pages/MainPage/index.ts create mode 100644 client/src/router.tsx create mode 100644 client/src/store/appErrorStore.ts create mode 100644 client/src/store/stepListStore.ts create mode 100644 client/src/store/totalExpenseAmountStore.ts create mode 100644 client/src/types/fetchErrorType.ts create mode 100644 client/src/types/serviceType.ts create mode 100644 client/src/utils/caculateExpense.ts create mode 100644 client/src/utils/captureError.ts create mode 100644 client/src/utils/getEventIdByUrl.ts create mode 100644 client/src/utils/getEventPageUrlByEnvironment.ts create mode 100644 client/src/utils/groupActions.ts create mode 100644 client/src/utils/isArraysEqual.ts create mode 100644 client/src/utils/objectToQueryString.ts create mode 100644 client/src/utils/sendLogToSentry.ts create mode 100644 client/src/utils/stepListToActions.ts create mode 100644 client/src/utils/validate/type.ts create mode 100644 client/src/utils/validate/validateEventName.ts create mode 100644 client/src/utils/validate/validateEventPassword.ts create mode 100644 client/src/utils/validate/validateMemberName.ts create mode 100644 client/src/utils/validate/validateMemberReportInAction.ts create mode 100644 client/src/utils/validate/validatePurchase.ts create mode 100644 client/tsconfig.json create mode 100644 client/webpack.common.mjs create mode 100644 client/webpack.dev.mjs create mode 100644 client/webpack.prod.mjs create mode 100644 server/.gitignore delete mode 100644 server/.gitkeep create mode 100644 server/Dockerfile create mode 100644 server/build.gradle create mode 100644 server/docs/24-08-04-erd.sql create mode 100644 server/docs/24-08-04-erd.svg create mode 100644 server/gradle/wrapper/gradle-wrapper.jar create mode 100644 server/gradle/wrapper/gradle-wrapper.properties create mode 100644 server/gradlew create mode 100644 server/gradlew.bat create mode 100644 server/settings.gradle create mode 100644 server/src/docs/asciidoc/billAction.adoc create mode 100644 server/src/docs/asciidoc/billActionDetail.adoc create mode 100644 server/src/docs/asciidoc/event.adoc create mode 100644 server/src/docs/asciidoc/index.adoc create mode 100644 server/src/docs/asciidoc/memberAction.adoc create mode 100644 server/src/docs/asciidoc/memberBillReport.adoc create mode 100644 server/src/main/java/server/haengdong/HaengdongApplication.java create mode 100644 server/src/main/java/server/haengdong/application/ActionService.java create mode 100644 server/src/main/java/server/haengdong/application/AuthService.java create mode 100644 server/src/main/java/server/haengdong/application/BillActionDetailService.java create mode 100644 server/src/main/java/server/haengdong/application/BillActionService.java create mode 100644 server/src/main/java/server/haengdong/application/EventService.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionFactory.java create mode 100644 server/src/main/java/server/haengdong/application/MemberActionService.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java create mode 100644 server/src/main/java/server/haengdong/application/response/ActionAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java create mode 100644 server/src/main/java/server/haengdong/application/response/MembersAppResponse.java create mode 100644 server/src/main/java/server/haengdong/config/AdminInterceptor.java create mode 100644 server/src/main/java/server/haengdong/config/RequestServletFilter.java create mode 100644 server/src/main/java/server/haengdong/config/WebMvcConfig.java create mode 100644 server/src/main/java/server/haengdong/domain/TokenProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/action/Action.java create mode 100644 server/src/main/java/server/haengdong/domain/action/ActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillAction.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetail.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/BillActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/CurrentMembers.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberAction.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberBillReport.java create mode 100644 server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/event/Event.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventRepository.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventStep.java create mode 100644 server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/domain/event/Password.java create mode 100644 server/src/main/java/server/haengdong/exception/AuthenticationException.java create mode 100644 server/src/main/java/server/haengdong/exception/ErrorResponse.java create mode 100644 server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java create mode 100644 server/src/main/java/server/haengdong/exception/HaengdongException.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java create mode 100644 server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java create mode 100644 server/src/main/java/server/haengdong/presentation/ActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/BillActionDetailController.java create mode 100644 server/src/main/java/server/haengdong/presentation/EventController.java create mode 100644 server/src/main/java/server/haengdong/presentation/MemberActionController.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/EventResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/MembersResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepResponse.java create mode 100644 server/src/main/java/server/haengdong/presentation/response/StepsResponse.java create mode 100644 server/src/main/resources/application.yml create mode 160000 server/src/main/resources/config create mode 100644 server/src/main/resources/logback-spring.xml create mode 100644 server/src/test/java/server/haengdong/application/ActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/BillActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/EventServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java create mode 100644 server/src/test/java/server/haengdong/application/MemberActionServiceTest.java create mode 100644 server/src/test/java/server/haengdong/application/ServiceTestSupport.java create mode 100644 server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java create mode 100644 server/src/test/java/server/haengdong/docs/RestDocsSupport.java create mode 100644 server/src/test/java/server/haengdong/domain/action/ActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/BillActionTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java create mode 100644 server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java create mode 100644 server/src/test/java/server/haengdong/domain/event/EventTest.java create mode 100644 server/src/test/java/server/haengdong/domain/event/PasswordTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/ActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java create mode 100644 server/src/test/java/server/haengdong/presentation/EventControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java create mode 100644 server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java create mode 100644 server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java create mode 100644 server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java create mode 100644 server/src/test/java/server/haengdong/support/fixture/Fixture.java diff --git a/.github/workflows/backend-dev.yml b/.github/workflows/backend-dev.yml new file mode 100644 index 000000000..a3257f028 --- /dev/null +++ b/.github/workflows/backend-dev.yml @@ -0,0 +1,72 @@ +name: backend-push + +on: + push: + branches: [ "be-dev" ] + +jobs: + build: + runs-on: [ self-hosted, backend-dev ] + + defaults: + run: + shell: bash + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + with: + token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + + - name: Build and push + run: | + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} --push . + + deploy: + needs: build + runs-on: [ self-hosted, backend-dev ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} + + - name: Docker run + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml new file mode 100644 index 000000000..f7daacd33 --- /dev/null +++ b/.github/workflows/backend-prod.yml @@ -0,0 +1,74 @@ +name: backend-push + +on: + push: + branches: [ "main" ] + paths: + - 'server/**' + +jobs: + build: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: ./server + + permissions: + contents: read + + steps: + - name: CheckOut + uses: actions/checkout@v4 + with: + token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v3 + + - name: Build and push + run: | + docker buildx build --platform linux/arm64 -t \ + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} --push . + + deploy: + needs: build + runs-on: [ self-hosted, backend-prod ] + steps: + - name: Docker remove + run: | + CONTAINER_IDS=$(sudo docker ps -qa) + if [ -n "$CONTAINER_IDS" ]; then + sudo docker rm -f $CONTAINER_IDS + else + echo "No running containers found." + fi + + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + + - name: Docker run + run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} diff --git a/.github/workflows/backend-pull-request.yml b/.github/workflows/backend-pull-request.yml new file mode 100644 index 000000000..df008fd97 --- /dev/null +++ b/.github/workflows/backend-pull-request.yml @@ -0,0 +1,44 @@ +name: backend-pull-request + +on: + pull_request: + branches: [ "main", "be-dev" ] + +jobs: + build: + runs-on: [ ubuntu-latest ] + + defaults: + run: + working-directory: ./server + + steps: + - name: CheckOut + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test with Gradle Wrapper + run: ./gradlew clean build + + - name: publish unit test results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: server/build/test-results/test/TEST-*.xml + + - name: add comments to a pull request + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: server/build/test-results/test/TEST-*.xml diff --git a/.github/workflows/design-pull-request.yml b/.github/workflows/design-pull-request.yml new file mode 100644 index 000000000..af168a976 --- /dev/null +++ b/.github/workflows/design-pull-request.yml @@ -0,0 +1,54 @@ +name: Storybook Deployment + +on: + pull_request: + branches: + - fe-dev + paths: + - 'HDesign/**' + +jobs: + chromatic: + name: Run Chromatic + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.15.1' + + - name: Cache dependencies + id: cache + uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: | + cd HDesign + npm install + + - name: Run lint + run: npm run lint + working-directory: ./HDesign + + - name: Run Chromatic + uses: chromaui/action@latest + id: publish_chromatic + with: + workingDir: HDesign + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + + - name: Comment on PR + uses: thollander/actions-comment-pull-request@v2 + with: + message: '🚀 **storybook**: ${{ steps.publish_chromatic.outputs.storybookUrl }}' diff --git a/.github/workflows/frontend-pull-request.yml b/.github/workflows/frontend-pull-request.yml new file mode 100644 index 000000000..c2749939b --- /dev/null +++ b/.github/workflows/frontend-pull-request.yml @@ -0,0 +1,49 @@ +name: frontend-pull-request + +on: + pull_request: + types: [opened, synchronize] + branches: [main, fe-dev] + paths: + - 'client/**' + +jobs: + test: + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + working-directory: ./client + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.15.1' + + - name: Install dependencies + working-directory: ./client + run: npm install + + - name: Run lint + working-directory: ./client + run: npm run lint + + - name: Run test + working-directory: ./client + run: npm run test + + - name: Cypress test + run: npm run dev & + env: + CI: true + + - name: Wait for the server to start + run: sleep 3 + + - name: Run Cypress tests + run: npm run cypress-run diff --git a/.github/workflows/pr-issue-close.yml b/.github/workflows/pr-issue-close.yml new file mode 100644 index 000000000..c37eb255d --- /dev/null +++ b/.github/workflows/pr-issue-close.yml @@ -0,0 +1,33 @@ +name: Close Issue on PR Merge + +on: + pull_request: + types: [closed] + +jobs: + close-issue: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Extract issue number from PR body + id: extract_issue + run: | + # Fetch PR body + PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}" \ + | jq -r '.body') + # Extract issue number from PR body using regex (customize if needed) + ISSUE_NUMBER=$(echo "$PR_BODY" | grep -oP '#\d+' | head -1 | sed 's/#//') + echo "ISSUE_NUMBER=$ISSUE_NUMBER" >> $GITHUB_ENV + - name: Close associated issue + if: env.ISSUE_NUMBER != '' + run: | + echo "Closing issue #${{ env.ISSUE_NUMBER }}" + curl -s -X PATCH -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d '{"state": "closed"}' \ + "https://api.github.com/repos/${{ github.repository }}/issues/${{ env.ISSUE_NUMBER }}" diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d013a93bc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "server/src/main/resources/config"] + branch = main + path = server/src/main/resources/config + url = https://github.com/woowacourse-teams/2024-haeng-dong-config.git diff --git a/HDesign/.gitignore b/HDesign/.gitignore new file mode 100644 index 000000000..b98928456 --- /dev/null +++ b/HDesign/.gitignore @@ -0,0 +1,12 @@ +logs +*.log +npm-debug.log* + +node_modules +dist + +.env + +storybook-static +*storybook.log +.DS_Store diff --git a/HDesign/.npmignore b/HDesign/.npmignore new file mode 100644 index 000000000..363c89306 --- /dev/null +++ b/HDesign/.npmignore @@ -0,0 +1,7 @@ +node_modules/ +src/ +tsconfig.json +.storybook/ +.eslintrc.json +.prettierrc +webpack.config.js \ No newline at end of file diff --git a/HDesign/.npmrc b/HDesign/.npmrc new file mode 100644 index 000000000..ece05f588 --- /dev/null +++ b/HDesign/.npmrc @@ -0,0 +1,2 @@ +engine-strict = true +legacy-peer-deps = true diff --git a/HDesign/.prettierrc b/HDesign/.prettierrc new file mode 100644 index 000000000..c025201f4 --- /dev/null +++ b/HDesign/.prettierrc @@ -0,0 +1,12 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "arrowParens": "avoid", + "endOfLine": "auto", + "jsxSingleQuote": false, + "bracketSpacing": false, + "proseWrap": "preserve" +} diff --git a/HDesign/.storybook/main.ts b/HDesign/.storybook/main.ts new file mode 100644 index 000000000..a1fa61591 --- /dev/null +++ b/HDesign/.storybook/main.ts @@ -0,0 +1,47 @@ +/** @type { import('@storybook/react-webpack5').StorybookConfig } */ +import type {StorybookConfig} from '@storybook/react-webpack5'; +import path from 'path'; + +const config: StorybookConfig = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + '@storybook/addon-webpack5-compiler-swc', + '@storybook/addon-onboarding', + '@storybook/addon-links', + '@storybook/addon-essentials', + '@chromatic-com/storybook', + '@storybook/addon-interactions', + ], + framework: { + name: '@storybook/react-webpack5', + options: {}, + }, + webpackFinal: async config => { + if (config.resolve) { + config.resolve.alias = { + ...config.resolve.alias, + '@components': path.resolve(__dirname, '../src/components'), + '@token': path.resolve(__dirname, '../src/token'), + '@type': path.resolve(__dirname, '../src/type'), + '@theme': path.resolve(__dirname, '../src/theme'), + '@assets': path.resolve(__dirname, '../src/assets'), + '@utils': path.resolve(__dirname, '../src/utils'), + }; + } + + config.module = config.module || {}; + config.module.rules = config.module.rules || []; + + const imageRule = config.module.rules.find(rule => rule?.['test']?.test('.svg')); + if (imageRule) { + imageRule['exclude'] = /\.svg$/; + } + + config.module.rules.push({ + test: /\.svg$/, + use: ['@svgr/webpack'], + }); + return config; + }, +}; +export default config; diff --git a/HDesign/.storybook/preview.tsx b/HDesign/.storybook/preview.tsx new file mode 100644 index 000000000..22008ad03 --- /dev/null +++ b/HDesign/.storybook/preview.tsx @@ -0,0 +1,41 @@ +/** @jsxImportSource @emotion/react */ + +import type {Preview} from '@storybook/react'; +import {HDesignProvider} from '../src/theme/HDesignProvider'; + +const preview: Preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + viewport: { + defaultViewport: { + styles: { + width: '375px', + height: '812px', + }, + }, + }, + backgrounds: { + default: 'gray', + values: [ + { + name: 'gray', + value: '#f3f3f3', + }, + ], + }, + }, + decorators: [ + Story => ( + + + + ), + ], +}; + +export default preview; diff --git a/HDesign/eslint.config.mjs b/HDesign/eslint.config.mjs new file mode 100644 index 000000000..e025936a4 --- /dev/null +++ b/HDesign/eslint.config.mjs @@ -0,0 +1,153 @@ +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; + +import {fixupConfigRules, fixupPluginRules} from '@eslint/compat'; +import react from 'eslint-plugin-react'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import _import from 'eslint-plugin-import'; +import prettier from 'eslint-plugin-prettier'; +import tsParser from '@typescript-eslint/parser'; +import js from '@eslint/js'; +import {FlatCompat} from '@eslint/eslintrc'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default [ + ...fixupConfigRules( + compat.extends( + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:import/typescript', + 'plugin:import/recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'prettier', + 'plugin:prettier/recommended', + ), + ), + { + plugins: { + react: fixupPluginRules(react), + '@typescript-eslint': fixupPluginRules(typescriptEslint), + import: fixupPluginRules(_import), + prettier: fixupPluginRules(prettier), + }, + + languageOptions: { + parser: tsParser, + }, + + settings: { + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + + typescript: { + directory: './lib', + }, + }, + + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + + 'import/ignore': ['lottie-react'], + }, + + rules: { + 'no-use-before-define': 0, + 'prettier/prettier': 'error', + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + 'import/prefer-default-export': 0, + 'import/no-named-as-default': 0, + 'import/namespace': 0, + 'import/extensions': 0, + 'import/no-cycle': 0, + 'react/no-unknown-property': 0, + 'react/jsx-filename-extension': [1, {extensions: ['.ts', '.tsx']}], + 'react/function-component-definition': 0, + 'react/jsx-props-no-spreading': 0, + 'react/jsx-key': 0, + 'react/button-has-type': 'off', + 'no-shadow': 0, + 'no-console': 0, + 'no-alert': 0, + 'react/no-children-prop': 'off', + 'react/no-array-index-key': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react-hooks/rules-of-hooks': 'off', + 'react/jsx-no-useless-fragment': 'off', + 'react/jsx-no-constructed-context-values': 'off', + 'jsx-a11y/click-events-have-key-events': 'off', + 'jsx-a11y/no-static-element-interactions': 'off', + + '@typescript-eslint/no-unused-vars': 0, + + // 'react/jsx-uses-vars': 'error', + // '@typescript-eslint/no-use-before-define': ['error'], + // '@typescript-eslint/explicit-module-boundary-types': 'error', + + 'import/order': [ + 'error', + { + 'newlines-between': 'always', + + groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], + + pathGroups: [ + { + pattern: 'react*', + group: 'external', + position: 'before', + }, + { + pattern: '@components/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@layouts/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@assets/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@theme/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@token/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@types/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@utils/*', + group: 'internal', + position: 'after', + }, + ], + }, + ], + }, + }, +]; diff --git a/HDesign/package-lock.json b/HDesign/package-lock.json new file mode 100644 index 000000000..fb92d2ae1 --- /dev/null +++ b/HDesign/package-lock.json @@ -0,0 +1,13707 @@ +{ + "name": "haengdong-design", + "version": "0.1.81", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "haengdong-design", + "version": "0.1.81", + "license": "ISC", + "dependencies": { + "@emotion/react": "^11.11.4", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@svgr/webpack": "^8.1.0", + "lottie-react": "^2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "devDependencies": { + "@chromatic-com/storybook": "^1.6.1", + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@storybook/addon-essentials": "^8.2.2", + "@storybook/addon-interactions": "^8.2.2", + "@storybook/addon-links": "^8.2.2", + "@storybook/addon-onboarding": "^8.2.2", + "@storybook/blocks": "^8.2.2", + "@storybook/react": "^8.2.2", + "@storybook/react-webpack5": "^8.2.3", + "@storybook/test": "^8.2.2", + "@swc/core": "^1.7.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "esbuild": "^0.23.0", + "eslint": "^9.8.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-storybook": "^0.8.0", + "file-loader": "^6.2.0", + "globals": "^15.8.0", + "prettier": "3.3.2", + "storybook": "^8.2.2", + "storybook-addon-react-router-v6": "^2.0.15", + "ts-loader": "^9.5.1", + "tsc-alias": "^1.8.10", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", + "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "dependencies": { + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", + "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", + "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", + "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-wrap-function": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", + "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "dependencies": { + "@babel/helper-function-name": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", + "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", + "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", + "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", + "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", + "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", + "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", + "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-flow": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", + "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.24.7.tgz", + "integrity": "sha512-7LidzZfUXyfZ8/buRW6qIIHBY8wAZ1OrY9c/wTr8YhZ6vMPo+Uc/CVFLYY1spZrEQlD4w5u8wjqk5NQ3OVqQKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", + "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", + "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", + "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.8.tgz", + "integrity": "sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", + "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.8", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.7.tgz", + "integrity": "sha512-NL3Lo0NorCU607zU3NwRyJbpaB6E3t0xtd3LfAQKDfkeX4/ggcDXvkmkW42QWT5owUeW/jAe4hn+2qvkV1IbfQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-flow-strip-types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", + "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.24.6.tgz", + "integrity": "sha512-WSuFCc2wCqMeXkz/i3yfAAsxwWflEgbVkZzivgAmXl/MxrXeoYFZOOPllbC8R8WTF7u61wSRQtDVZ1879cdu6w==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/register/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/types": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@chromatic-com/storybook": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-1.6.1.tgz", + "integrity": "sha512-x1x1NB3j4xpfeSWKr96emc+7ZvfsvH+/WVb3XCjkB24PPbT8VZXb3mJSAQMrSzuQ8+eQE9kDogYHH9Fj3tb/Cw==", + "dev": true, + "dependencies": { + "chromatic": "^11.4.0", + "filesize": "^10.0.12", + "jsonfile": "^6.1.0", + "react-confetti": "^6.1.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16.0.0", + "yarn": ">=1.22.18" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@chromatic-com/storybook/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", + "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", + "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.0.tgz", + "integrity": "sha512-s9Wi/p25+KbzxKlDm3VshQdImhWk+cbdblhwGNnyCU5lpSwtWa4v7VQCxSki0FAUrGA3s8nCWgYzAH41mwQVKQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dev": true, + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.1.tgz", + "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/addon-actions": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-8.2.2.tgz", + "integrity": "sha512-SN4cSRt3f0qXi5te+yhMseSdQuZntA8lGlASbRmN77YQTpIaGsNiH88xFoky0s9qz531hiRfU1R0ZSMylBwSKw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@types/uuid": "^9.0.1", + "dequal": "^2.0.2", + "polished": "^4.2.2", + "uuid": "^9.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-actions/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.2.2.tgz", + "integrity": "sha512-m/xJe7uKL+kfJx7pQcHwAeIvJ3tdLIpDGrMAVDNDJHcAxfe44cFjIInaV/1HKf3y5Awap+DZFW66ekkxuI9zzA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-controls": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-8.2.2.tgz", + "integrity": "sha512-y241aOANGzT5XBADUIvALwG/xF5eC6UItzmWJaFvOzSBCq74GIA0+Hu9atyFdvFQbXOrdvPWC4jR+9iuBFRxAA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.2.2.tgz", + "integrity": "sha512-qk/yjAR9RpsSrKLLbeCgb6u58c8TmYqyJSnXgbAozZZNKHBWlIpvZ/hTNYud8qo0coPlxnLdjnZf32TykWGlAg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@mdx-js/react": "^3.0.0", + "@storybook/blocks": "8.2.2", + "@storybook/csf-plugin": "8.2.2", + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "8.2.2", + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "fs-extra": "^11.1.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "rehype-external-links": "^3.0.0", + "rehype-slug": "^6.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-docs/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-8.2.2.tgz", + "integrity": "sha512-yN//BFMbSvNV0+Sll2hcKmgJX06TUKQDm6pZimUjkXczFtOmK7K/UdDmKjWS+qjhfJdWpxdRoEpxoHvvRmNfsA==", + "dev": true, + "dependencies": { + "@storybook/addon-actions": "8.2.2", + "@storybook/addon-backgrounds": "8.2.2", + "@storybook/addon-controls": "8.2.2", + "@storybook/addon-docs": "8.2.2", + "@storybook/addon-highlight": "8.2.2", + "@storybook/addon-measure": "8.2.2", + "@storybook/addon-outline": "8.2.2", + "@storybook/addon-toolbars": "8.2.2", + "@storybook/addon-viewport": "8.2.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-8.2.2.tgz", + "integrity": "sha512-yDTRzzL+IJAymgY32xoZl09BGBVmPOUV2wVNGYcZkkBLvz2GSQMTfUe1/7F4jAx//+rFBu48/MQzsTC7Bk8kPw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-8.2.2.tgz", + "integrity": "sha512-zRRuUwm/l41JtTUgjIoQTUgLT99Hsdz9cqKca/8NYo1MGBdEcKE41DH4aBIzKaOKFu7p9q00/o/X1EqYX4LMUA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "8.2.2", + "@storybook/test": "8.2.2", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-links": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-8.2.2.tgz", + "integrity": "sha512-eGh7O7SgTJMtnuXC0HlRPOegu1njcJS2cnVqjbzjvjxsPSBhbHpdYMi9Q9E7al/FKuqMUOjIR9YLIlmK1AJaqA==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-measure": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-8.2.2.tgz", + "integrity": "sha512-3rCo/aMltt5FrBVdr2dYlD8HlE2q9TLKGJZnwh9on4QyL6ArHbdYw0LmyHe/LrFahJ49w1XQZBMSJcAdRkkS7w==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-onboarding": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-onboarding/-/addon-onboarding-8.2.2.tgz", + "integrity": "sha512-dCdE8Mt/JW6cq6dY7co35Sul/bAkUT3ixaxBrUagFUYUQ/PTYM6p4/B+45RURD5S9z8LVHH1rVgmEeScm3U78w==", + "dev": true, + "dependencies": { + "react-confetti": "^6.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-outline": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-8.2.2.tgz", + "integrity": "sha512-Y+PQtfTNO8GLX5nz+3x5AMfHNvdGvBXazJ29+Rl1ygYN1+Q9ZhRJDE1kAK0wLxb7CG14peAgdYEaQb3Rduv7HQ==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-8.2.2.tgz", + "integrity": "sha512-JGOueOc3EPljlCl9dVSQee0aMYoqGNvN0UH+R6wYJ3bDZ+tUG/iYpsZVPUOvS8vzp3Imk5Is1kzQbQYJtzdGLg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-8.2.2.tgz", + "integrity": "sha512-gkZ8bsjGGP0NuevkT2iKC+szezSy+w4BrBDknf490mRU2K/B2e7TGojf/j/AtxzILMzD4IKzKUXbE/zwcqjZvA==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/addon-webpack5-compiler-swc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.5.tgz", + "integrity": "sha512-1NlM3noit2vA22OyWb8Ma2lhcEKCS1Snv2kr+EkaVABUqNDfVc9AD/GgYQhF7F/2CoF5N2JU7uzXDzFHd5TzZg==", + "dependencies": { + "@swc/core": "^1.7.3", + "swc-loader": "^0.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@storybook/blocks": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-8.2.2.tgz", + "integrity": "sha512-av0Tryg4toDl2L/d1ABErtsAk9wvM1su6+M4wq5/Go50sk5IjGTldhbZFa9zNOohxLkZwaj0Q5xAgJ1Y+m5KrQ==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/global": "^5.0.0", + "@storybook/icons": "^1.2.5", + "@types/lodash": "^4.14.167", + "color-convert": "^2.0.1", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "markdown-to-jsx": "^7.4.5", + "memoizerific": "^1.11.3", + "polished": "^4.2.2", + "react-colorful": "^5.1.2", + "telejson": "^7.2.0", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-8.2.3.tgz", + "integrity": "sha512-yU9rtcVpo12vD8m/nbdepyJ09K937ZnSsrvIM9XfzbxXA/+p4Cov9Rjg1VfoWyRd1ApxaztSktQlawBlb6bKEA==", + "dev": true, + "dependencies": { + "@storybook/core-webpack": "8.2.3", + "@types/node": "^18.0.0", + "@types/semver": "^7.3.4", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "cjs-module-lexer": "^1.2.3", + "constants-browserify": "^1.0.0", + "css-loader": "^6.7.1", + "es-module-lexer": "^1.5.0", + "express": "^4.19.2", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "fs-extra": "^11.1.0", + "html-webpack-plugin": "^5.5.0", + "magic-string": "^0.30.5", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "url": "^0.11.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^6.1.2", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.3" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz", + "integrity": "sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/@storybook/builder-webpack5/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", + "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@storybook/codemod": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-8.2.2.tgz", + "integrity": "sha512-wRUVKLHVUhbLJYKW3QOufUxJGwaUT4jTCD8+HOGpHPdJO3NrwXu186xt4tuPZO2Y/NnacPeCQPsaK5ok4O8o7A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/core": "8.2.2", + "@storybook/csf": "0.1.11", + "@types/cross-spawn": "^6.0.2", + "cross-spawn": "^7.0.3", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "lodash": "^4.17.21", + "prettier": "^3.1.1", + "recast": "^0.23.5", + "tiny-invariant": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/codemod/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/codemod/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/core": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/core/-/core-8.2.2.tgz", + "integrity": "sha512-L4ojYI+Os/i5bCReDIlFgEDQSS94mbJlNU9WRzEGZpqNC5/hbFEC9Tip7P1MiRx9NrewkzU7b+UCP7mi3e4drQ==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@types/express": "^4.17.21", + "@types/node": "^18.0.0", + "browser-assert": "^1.2.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0", + "esbuild-register": "^3.5.0", + "express": "^4.19.2", + "process": "^0.11.10", + "recast": "^0.23.5", + "util": "^0.12.4", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-8.2.3.tgz", + "integrity": "sha512-0M4mJM6i4Oqp1javRMg/8wJW7VJ6p6Z8GKp6evfHLEWZAzdnexQIkPd5FFaDlFXbQNH1H0oJ+6ei4nIBtEegKg==", + "dev": true, + "dependencies": { + "@types/node": "^18.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.3" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/core/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@storybook/core/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/core/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/@storybook/csf": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.1.11.tgz", + "integrity": "sha512-dHYFQH3mA+EtnCkHXzicbLgsvzYjcDJ1JWsogbItZogkPHgSJM/Wr71uMkcvw8v9mmCyP4NpXJuu6bPoVsOnzg==", + "dev": true, + "dependencies": { + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-8.2.2.tgz", + "integrity": "sha512-3K2RUpDDvq3DT46qAIj2VBC+fzTTebRUcZUsRfS6G1AzaX9p25iClEHiwcJacFkgQKhkci8A/Ly3Z4JJ3b4Pgw==", + "dev": true, + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true + }, + "node_modules/@storybook/icons": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.2.9.tgz", + "integrity": "sha512-cOmylsz25SYXaJL/gvTk/dl3pyk7yBFRfeXTsHvTA3dfhoU/LWSq0NKL9nM7WBasJyn6XPSGnLS4RtKXLw5EUg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/instrumenter": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.2.2.tgz", + "integrity": "sha512-refwnHqKHhya45MgqakhMG0jKhTiEIAl0aOwAaQy9+zf9ncMIYQAXRQsSZ2Z188lFWE24wbeHKteb62a5ZfWwQ==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@vitest/utils": "^1.3.1", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/preset-react-webpack": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-8.2.3.tgz", + "integrity": "sha512-i886+vCMGlpFgOAOIg6BxSHgt38MXS6gqNX8Z65KVVIlI6i/9WqEQeHYfukbdGvVZ96cYWmdrnqUieIIkdCdBw==", + "dev": true, + "dependencies": { + "@storybook/core-webpack": "8.2.3", + "@storybook/react": "8.2.3", + "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", + "@types/node": "^18.0.0", + "@types/semver": "^7.3.4", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "magic-string": "^0.30.5", + "react-docgen": "^7.0.0", + "resolve": "^1.22.8", + "semver": "^7.3.7", + "tsconfig-paths": "^4.2.0", + "webpack": "5" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-8.2.3.tgz", + "integrity": "sha512-818F6pJWFBiwG0r6DiUVrV+qndwbIso2gtgJoituBgIJO2eIzNmkPNSsckbaR7u+FpE4dWiIIhmDVZSnRwvDlA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "8.2.3", + "@types/escodegen": "^0.0.6", + "@types/estree": "^0.0.51", + "@types/node": "^18.0.0", + "acorn": "^7.4.1", + "acorn-jsx": "^5.3.1", + "acorn-walk": "^7.2.0", + "escodegen": "^2.1.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "react-element-to-jsx-string": "^15.0.0", + "semver": "^7.3.7", + "ts-dedent": "^2.0.0", + "type-fest": "~2.19", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin": { + "version": "1.0.6--canary.9.0c3f3b7.0", + "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.6--canary.9.0c3f3b7.0.tgz", + "integrity": "sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "find-cache-dir": "^3.3.1", + "flat-cache": "^3.0.4", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^2.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "typescript": ">= 4.x", + "webpack": ">= 4" + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@storybook/react-dom-shim": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.2.tgz", + "integrity": "sha512-4fb1/yT9WXHzHjs0In6orIEZxga5eXd9UaXEFGudBgowCjDUVP9LabDdKTbGusz20lfaAkATsRG/W+EcSLoh8w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.2" + } + }, + "node_modules/@storybook/react-webpack5": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-8.2.3.tgz", + "integrity": "sha512-lcm73r8S5Uy2ENuFDSR07fW+KRSYGNcrF53VItP+rgFZHrOm7gaeebrjSIA6r4tQwdd9218VaqpQGFrKAURS2w==", + "dev": true, + "dependencies": { + "@storybook/builder-webpack5": "8.2.3", + "@storybook/preset-react-webpack": "8.2.3", + "@storybook/react": "8.2.3", + "@types/node": "^18.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3", + "typescript": ">= 4.2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-webpack5/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/@storybook/react-dom-shim": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-8.2.3.tgz", + "integrity": "sha512-N8AsM6N1S867GGWt2J2q5oY5ryqxohh3y1HqNtjg+wXf5+RkTD6M2Cgqe6p+JHz81nDKyvvVzP60MvvDhY5VOA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^8.2.3" + } + }, + "node_modules/@storybook/react/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@storybook/react/node_modules/@types/node": { + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@storybook/react/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@storybook/test": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.2.2.tgz", + "integrity": "sha512-X2qAKErjTh1X7XLAZqCMtU0ZK8JuwdKmgiqU0oXWxIDmCX6/Dm9ZIcdMZHs/S+K/UnIByjNlQpTShLVfRUeN1w==", + "dev": true, + "dependencies": { + "@storybook/csf": "0.1.11", + "@storybook/instrumenter": "8.2.2", + "@testing-library/dom": "10.1.0", + "@testing-library/jest-dom": "6.4.5", + "@testing-library/user-event": "14.5.2", + "@vitest/expect": "1.6.0", + "@vitest/spy": "1.6.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^8.2.2" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/core": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.6.tgz", + "integrity": "sha512-FZxyao9eQks1MRmUshgsZTmlg/HB2oXK5fghkoWJm/1CU2q2kaJlVDll2as5j+rmWiwkp0Gidlq8wlXcEEAO+g==", + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.12" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.7.6", + "@swc/core-darwin-x64": "1.7.6", + "@swc/core-linux-arm-gnueabihf": "1.7.6", + "@swc/core-linux-arm64-gnu": "1.7.6", + "@swc/core-linux-arm64-musl": "1.7.6", + "@swc/core-linux-x64-gnu": "1.7.6", + "@swc/core-linux-x64-musl": "1.7.6", + "@swc/core-win32-arm64-msvc": "1.7.6", + "@swc/core-win32-ia32-msvc": "1.7.6", + "@swc/core-win32-x64-msvc": "1.7.6" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.6.tgz", + "integrity": "sha512-6lYHey84ZzsdtC7UuPheM4Rm0Inzxm6Sb8U6dmKc4eCx8JL0LfWG4LC5RsdsrTxnjTsbriWlnhZBffh8ijUHIQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, + "node_modules/@swc/types": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", + "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.1.0.tgz", + "integrity": "sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.3.2", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/bun": "latest", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/bun": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true + }, + "node_modules/@types/emscripten": { + "version": "1.39.13", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", + "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==", + "dev": true + }, + "node_modules/@types/escodegen": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", + "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.56.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", + "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", + "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", + "dev": true + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", + "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", + "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/type-utils": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", + "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/utils": "7.16.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", + "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", + "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", + "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", + "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/visitor-keys": "7.16.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", + "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.16.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "dev": true, + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@vitest/utils/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@vitest/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/fslib": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@yarnpkg/fslib/-/fslib-2.10.3.tgz", + "integrity": "sha512-41H+Ga78xT9sHvWLlFOZLIhtU6mTGZ20pZ29EiZa97vnxdohJD2AF42rCoAoWfqUz486xY6fhjMH+DYEM9r14A==", + "dev": true, + "dependencies": { + "@yarnpkg/libzip": "^2.3.0", + "tslib": "^1.13.0" + }, + "engines": { + "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" + } + }, + "node_modules/@yarnpkg/fslib/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@yarnpkg/libzip": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/libzip/-/libzip-2.3.0.tgz", + "integrity": "sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==", + "dev": true, + "dependencies": { + "@types/emscripten": "^1.39.6", + "tslib": "^1.13.0" + }, + "engines": { + "node": ">=12 <14 || 14.2 - 14.9 || >14.10.0" + } + }, + "node_modules/@yarnpkg/libzip/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", + "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chromatic": { + "version": "11.5.5", + "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-11.5.5.tgz", + "integrity": "sha512-YS0GJwegF0vpMbwZE68/xJlI4SlUGMqI78V2ATAF19YwTHaq8jGP1CPQGKUSlgWUhzPtyu3ELy6Dvv/owYljAg==", + "dev": true, + "bin": { + "chroma": "dist/bin.js", + "chromatic": "dist/bin.js", + "chromatic-cli": "dist/bin.js" + }, + "peerDependencies": { + "@chromatic-com/cypress": "^0.*.* || ^1.0.0", + "@chromatic-com/playwright": "^0.*.* || ^1.0.0" + }, + "peerDependenciesMeta": { + "@chromatic-com/cypress": { + "optional": true + }, + "@chromatic-com/playwright": { + "optional": true + } + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.827", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.827.tgz", + "integrity": "sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/endent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", + "dev": true, + "dependencies": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } + }, + "node_modules/esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", + "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.8.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "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.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", + "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-storybook": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.8.0.tgz", + "integrity": "sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.0.1", + "@typescript-eslint/utils": "^5.62.0", + "requireindex": "^1.2.0", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "eslint": ">=6" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-1.2.0.tgz", + "integrity": "sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==", + "dev": true, + "dependencies": { + "walk-up-path": "^3.0.1" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-entry-cache/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/filesize": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.4.tgz", + "integrity": "sha512-ryBwPIIeErmxgPnm6cbESAzXjuEFubs+yKYLBZvg3CaiNcmkJChoOGcBSrZ6IwkMwPABwPpVXE6IlNdGJJrvEg==", + "dev": true, + "engines": { + "node": ">= 10.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/flow-parser": { + "version": "0.239.1", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.239.1.tgz", + "integrity": "sha512-topOrETNxJ6T2gAnQiWqAlzGPj8uI2wtmNOlDIMNB+qyvGJZ6R++STbUOTAYmvPhOMz2gXnXPH0hOvURYmrBow==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/giget": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz", + "integrity": "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==", + "dev": true, + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.2.3", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.3", + "nypm": "^0.3.8", + "ohash": "^1.1.3", + "pathe": "^1.1.2", + "tar": "^6.2.0" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", + "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", + "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jscodeshift": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.15.2.tgz", + "integrity": "sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.23.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/preset-flow": "^7.22.15", + "@babel/preset-typescript": "^7.23.0", + "@babel/register": "^7.22.15", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.23.3", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + }, + "peerDependenciesMeta": { + "@babel/preset-env": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lottie-react": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.0.tgz", + "integrity": "sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true + }, + "node_modules/markdown-to-jsx": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.7.tgz", + "integrity": "sha512-0+ls1IQZdU6cwM1yu0ZjjiVWYtkbExSyUIFU2ZeDIFuZM1W42Mh4OlJ4nb4apX4H8smxDHRdFaoIVJGwfv5hkg==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/mylas": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/mylas/-/mylas-2.1.13.tgz", + "integrity": "sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/raouldeheer" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-dir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-dir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.4.tgz", + "integrity": "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nypm": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.9.tgz", + "integrity": "sha512-BI2SdqqTHg2d4wJh8P9A1W+bslg33vOE9IZDY6eR2QC+Pu1iNBVZUqczrd43rJb+fMzHU7ltAYKsEFY/kHMFcw==", + "dev": true, + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.2.3", + "execa": "^8.0.1", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/nypm/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/nypm/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/nypm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nypm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/objectorarray": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", + "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", + "dev": true + }, + "node_modules/ohash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", + "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", + "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", + "dev": true, + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.1", + "pathe": "^1.1.2" + } + }, + "node_modules/plimit-lit": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.6.1.tgz", + "integrity": "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==", + "dev": true, + "dependencies": { + "queue-lit": "^1.5.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-lit": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/queue-lit/-/queue-lit-1.5.2.tgz", + "integrity": "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "dev": true, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-confetti": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-confetti/-/react-confetti-6.1.0.tgz", + "integrity": "sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==", + "dev": true, + "dependencies": { + "tween-functions": "^1.2.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-docgen": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.0.3.tgz", + "integrity": "sha512-i8aF1nyKInZnANZ4uZrH49qn1paRgBZ7wZiCNBMnenlPzEv0mRl+ShpTVEI6wZNl8sSc79xZkivtgLKQArcanQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9", + "@types/babel__core": "^7.18.0", + "@types/babel__traverse": "^7.18.0", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", + "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "dev": true, + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, + "dependencies": { + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "peerDependencies": { + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-element-to-jsx-string/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, + "node_modules/react-inspector": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", + "integrity": "sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==", + "dev": true, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-router": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.1.tgz", + "integrity": "sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==", + "dependencies": { + "@remix-run/router": "1.17.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.1.tgz", + "integrity": "sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==", + "dependencies": { + "@remix-run/router": "1.17.1", + "react-router": "6.24.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dev": true, + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/storybook": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-8.2.2.tgz", + "integrity": "sha512-xDT9gyzAEFQNeK7P+Mj/8bNzN+fbm6/4D6ihdSzmczayjydpNjMs74HDHMY6S4Bfu6tRVyEK2ALPGnr6ZVofBA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/types": "^7.24.0", + "@storybook/codemod": "8.2.2", + "@storybook/core": "8.2.2", + "@types/semver": "^7.3.4", + "@yarnpkg/fslib": "2.10.3", + "@yarnpkg/libzip": "2.3.0", + "chalk": "^4.1.0", + "commander": "^6.2.1", + "cross-spawn": "^7.0.3", + "detect-indent": "^6.1.0", + "envinfo": "^7.7.3", + "execa": "^5.0.0", + "fd-package-json": "^1.2.0", + "find-up": "^5.0.0", + "fs-extra": "^11.1.0", + "giget": "^1.0.0", + "globby": "^14.0.1", + "jscodeshift": "^0.15.1", + "leven": "^3.1.0", + "ora": "^5.4.1", + "prettier": "^3.1.1", + "prompts": "^2.4.0", + "semver": "^7.3.7", + "strip-json-comments": "^3.0.1", + "tempy": "^3.1.0", + "tiny-invariant": "^1.3.1", + "ts-dedent": "^2.0.0" + }, + "bin": { + "getstorybook": "bin/index.cjs", + "sb": "bin/index.cjs", + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook-addon-react-router-v6": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/storybook-addon-react-router-v6/-/storybook-addon-react-router-v6-2.0.15.tgz", + "integrity": "sha512-4vOYIQwehlQLyXaCT9K0Iu0po2Z+pANGsqkfm/BQuAEjE9MoN7vrsrQLHINhKbmQVtNMmuS/oBR3GGNbqQ1gew==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "compare-versions": "^6.0.0", + "react-inspector": "6.0.2" + }, + "peerDependencies": { + "@storybook/blocks": "^7.0.0", + "@storybook/channels": "^7.0.0", + "@storybook/components": "^7.0.0", + "@storybook/core-events": "^7.0.0", + "@storybook/manager-api": "^7.0.0", + "@storybook/preview-api": "^7.0.0", + "@storybook/theming": "^7.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-router-dom": "^6.4.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/storybook/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/storybook/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/storybook/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/storybook/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/swc-loader": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", + "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "peerDependencies": { + "@swc/core": "^1.2.147", + "webpack": ">=2" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/telejson": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.2.0.tgz", + "integrity": "sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/temp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/temp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/temp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.31.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", + "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsc-alias": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.10.tgz", + "integrity": "sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "globby": "^11.0.4", + "mylas": "^2.1.9", + "normalize-path": "^3.0.0", + "plimit-lit": "^1.2.6" + }, + "bin": { + "tsc-alias": "dist/bin/index.js" + } + }, + "node_modules/tsc-alias/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tween-functions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", + "integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", + "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.16.0", + "@typescript-eslint/parser": "7.16.0", + "@typescript-eslint/utils": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", + "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.16.0", + "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/ufo": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.11.0.tgz", + "integrity": "sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "chokidar": "^3.6.0", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.6.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "dev": true, + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "node_modules/url/node_modules/qs": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", + "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-hot-middleware": { + "version": "2.26.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz", + "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", + "dev": true, + "dependencies": { + "ansi-html-community": "0.0.8", + "html-entities": "^2.1.0", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/HDesign/package.json b/HDesign/package.json new file mode 100644 index 000000000..062987bf1 --- /dev/null +++ b/HDesign/package.json @@ -0,0 +1,72 @@ +{ + "name": "haengdong-design", + "version": "0.1.81", + "description": "", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "start": "webpack serve ", + "build": "rm -rf dist && mkdir dist && tsc && cp -r ./src/assets ./dist && tsc-alias", + "storybook": "storybook dev -p 6006", + "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", + "format": "prettier --write {src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'", + "build-storybook": "storybook build" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@chromatic-com/storybook": "^1.6.1", + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@storybook/addon-essentials": "^8.2.2", + "@storybook/addon-interactions": "^8.2.2", + "@storybook/addon-links": "^8.2.2", + "@storybook/addon-onboarding": "^8.2.2", + "@storybook/blocks": "^8.2.2", + "@storybook/react": "^8.2.2", + "@storybook/react-webpack5": "^8.2.3", + "@storybook/test": "^8.2.2", + "@swc/core": "^1.7.6", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "esbuild": "^0.23.0", + "eslint": "^9.8.0", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-storybook": "^0.8.0", + "file-loader": "^6.2.0", + "globals": "^15.8.0", + "prettier": "3.3.2", + "storybook": "^8.2.2", + "storybook-addon-react-router-v6": "^2.0.15", + "ts-loader": "^9.5.1", + "tsc-alias": "^1.8.10", + "typescript": "^5.5.3", + "typescript-eslint": "^7.16.0" + }, + "dependencies": { + "@emotion/react": "^11.11.4", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@svgr/webpack": "^8.1.0", + "lottie-react": "^2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "npm": ">=10.7.0", + "node": ">=20.15.1" + } +} diff --git a/HDesign/src/assets/buljusa.svg b/HDesign/src/assets/buljusa.svg new file mode 100644 index 000000000..fe5c47534 --- /dev/null +++ b/HDesign/src/assets/buljusa.svg @@ -0,0 +1,4 @@ + + + + diff --git a/HDesign/src/assets/confirm.svg b/HDesign/src/assets/confirm.svg new file mode 100644 index 000000000..ef31a5152 --- /dev/null +++ b/HDesign/src/assets/confirm.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/HDesign/src/assets/error.svg b/HDesign/src/assets/error.svg new file mode 100644 index 000000000..479cae34a --- /dev/null +++ b/HDesign/src/assets/error.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/HDesign/src/assets/index.ts b/HDesign/src/assets/index.ts new file mode 100644 index 000000000..a9c277581 --- /dev/null +++ b/HDesign/src/assets/index.ts @@ -0,0 +1,7 @@ +export {default as InputDelete} from '@assets/inputDelete.svg'; +export {default as Buljusa} from '@assets/buljusa.svg'; +export {default as Error} from '@assets/error.svg'; +export {default as Confirm} from '@assets/confirm.svg'; +export {default as Trash} from '@assets/trash.svg'; +export {default as Search} from '@assets/search.svg'; +export {default as RightChevron} from '@assets/rightChevron.svg'; diff --git a/HDesign/src/assets/inputDelete.svg b/HDesign/src/assets/inputDelete.svg new file mode 100644 index 000000000..4356bb854 --- /dev/null +++ b/HDesign/src/assets/inputDelete.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/HDesign/src/assets/loadingAnimation.json b/HDesign/src/assets/loadingAnimation.json new file mode 100644 index 000000000..4f507a7ea --- /dev/null +++ b/HDesign/src/assets/loadingAnimation.json @@ -0,0 +1,1176 @@ +{ + "nm": "Main Scene", + "ddd": 0, + "h": 48, + "w": 128, + "meta": { + "g": "@lottiefiles/creator 1.24.1" + }, + "layers": [ + { + "ty": 0, + "nm": " Loading Dots", + "sr": 1, + "st": 0, + "op": 81, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + 962.9629629629629, + 540.7407407407408 + ] + }, + "s": { + "a": 0, + "k": [ + 27, + 27 + ] + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 0, + "k": [ + 64.25999999999999, + 24.2 + ] + }, + "r": { + "a": 0, + "k": 0 + }, + "sa": { + "a": 0, + "k": 0 + }, + "o": { + "a": 0, + "k": 100 + } + }, + "w": 1920, + "h": 1080, + "refId": "precomp_Loading Dots_139596b3-8049-4b90-9165-55e00cf10251", + "ind": 1 + } + ], + "v": "5.7.0", + "fr": 60, + "op": 81, + "ip": 0, + "assets": [ + { + "nm": "Loading Dots", + "id": "precomp_Loading Dots_139596b3-8049-4b90-9165-55e00cf10251", + "fr": 60, + "layers": [ + { + "ty": 4, + "nm": "Dot4", + "sr": 1, + "st": 0, + "op": 360, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + -284, + 92, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 50, + 50, + 100 + ], + "t": 25 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 75, + 75, + 100 + ], + "t": 39 + }, + { + "s": [ + 50, + 50, + 100 + ], + "t": 55 + } + ], + "ix": 6 + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 1142, + 540, + 0 + ], + "t": 25 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 1142, + 500, + 0 + ], + "t": 39 + }, + { + "s": [ + 1142, + 540, + 0 + ], + "t": 55 + } + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "sa": { + "a": 0, + "k": 0 + } + }, + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Ellipse 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "el", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Ellipse", + "nm": "Ellipse Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 3 + }, + "s": { + "a": 0, + "k": [ + 120, + 120 + ], + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { + "a": 1, + "k": [ + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 25 + }, + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.7098, + 0.4588, + 1 + ], + "t": 39 + }, + { + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 55 + } + ], + "ix": 4 + }, + "r": 1, + "o": { + "a": 0, + "k": 100, + "ix": 5 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "p": { + "a": 0, + "k": [ + -284, + 92 + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + } + } + ] + } + ], + "ind": 1 + }, + { + "ty": 4, + "nm": "Dot3", + "sr": 1, + "st": 0, + "op": 360, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + -284, + 92, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 50, + 50, + 100 + ], + "t": 17 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 75, + 75, + 100 + ], + "t": 31 + }, + { + "s": [ + 50, + 50, + 100 + ], + "t": 47 + } + ], + "ix": 6 + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 1022, + 540, + 0 + ], + "t": 17 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 1022, + 500, + 0 + ], + "t": 31 + }, + { + "s": [ + 1022, + 540, + 0 + ], + "t": 47 + } + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "sa": { + "a": 0, + "k": 0 + } + }, + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Ellipse 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "el", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Ellipse", + "nm": "Ellipse Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 3 + }, + "s": { + "a": 0, + "k": [ + 120, + 120 + ], + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { + "a": 1, + "k": [ + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 17 + }, + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.7098, + 0.4588, + 1 + ], + "t": 31 + }, + { + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 47 + } + ], + "ix": 4 + }, + "r": 1, + "o": { + "a": 0, + "k": 100, + "ix": 5 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "p": { + "a": 0, + "k": [ + -284, + 92 + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + } + } + ] + } + ], + "ind": 2 + }, + { + "ty": 4, + "nm": "Dot2", + "sr": 1, + "st": 0, + "op": 360, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + -284, + 92, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 50, + 50, + 100 + ], + "t": 9 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 75, + 75, + 100 + ], + "t": 23 + }, + { + "s": [ + 50, + 50, + 100 + ], + "t": 39 + } + ], + "ix": 6 + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 902, + 540, + 0 + ], + "t": 9 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 902, + 500, + 0 + ], + "t": 23 + }, + { + "s": [ + 902, + 540, + 0 + ], + "t": 39 + } + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "sa": { + "a": 0, + "k": 0 + } + }, + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Ellipse 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "el", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Ellipse", + "nm": "Ellipse Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 3 + }, + "s": { + "a": 0, + "k": [ + 120, + 120 + ], + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { + "a": 1, + "k": [ + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 9 + }, + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.7098, + 0.4588, + 1 + ], + "t": 23 + }, + { + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 39 + } + ], + "ix": 4 + }, + "r": 1, + "o": { + "a": 0, + "k": 100, + "ix": 5 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "p": { + "a": 0, + "k": [ + -284, + 92 + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + } + } + ] + } + ], + "ind": 3 + }, + { + "ty": 4, + "nm": "Dot1", + "sr": 1, + "st": 0, + "op": 360, + "ip": 0, + "hd": false, + "ddd": 0, + "bm": 0, + "hasMask": false, + "ao": 0, + "ks": { + "a": { + "a": 0, + "k": [ + -284, + 92, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 50, + 50, + 100 + ], + "t": 0 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 75, + 75, + 100 + ], + "t": 14 + }, + { + "s": [ + 50, + 50, + 100 + ], + "t": 30 + } + ], + "ix": 6 + }, + "sk": { + "a": 0, + "k": 0 + }, + "p": { + "a": 1, + "k": [ + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 782, + 540, + 0 + ], + "t": 0 + }, + { + "o": { + "x": 0.333, + "y": 0 + }, + "i": { + "x": 0.667, + "y": 1 + }, + "s": [ + 782, + 500, + 0 + ], + "t": 14 + }, + { + "s": [ + 782, + 540, + 0 + ], + "t": 30 + } + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "sa": { + "a": 0, + "k": 0 + } + }, + "shapes": [ + { + "ty": "gr", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Group", + "nm": "Ellipse 1", + "ix": 1, + "cix": 2, + "np": 3, + "it": [ + { + "ty": "el", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Shape - Ellipse", + "nm": "Ellipse Path 1", + "d": 1, + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 3 + }, + "s": { + "a": 0, + "k": [ + 120, + 120 + ], + "ix": 2 + } + }, + { + "ty": "fl", + "bm": 0, + "hd": false, + "mn": "ADBE Vector Graphic - Fill", + "nm": "Fill 1", + "c": { + "a": 1, + "k": [ + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 0 + }, + { + "o": { + "x": 0.167, + "y": 0.167 + }, + "i": { + "x": 0.833, + "y": 0.833 + }, + "s": [ + 0.7098, + 0.4588, + 1 + ], + "t": 14 + }, + { + "s": [ + 0.8784, + 0.7804, + 0.9961 + ], + "t": 30 + } + ], + "ix": 4 + }, + "r": 1, + "o": { + "a": 0, + "k": 100, + "ix": 5 + } + }, + { + "ty": "tr", + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "p": { + "a": 0, + "k": [ + -284, + 92 + ], + "ix": 2 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + } + } + ] + } + ], + "ind": 4 + } + ] + } + ] +} \ No newline at end of file diff --git a/HDesign/src/assets/rightChevron.svg b/HDesign/src/assets/rightChevron.svg new file mode 100644 index 000000000..5cd777f1b --- /dev/null +++ b/HDesign/src/assets/rightChevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/HDesign/src/assets/search.svg b/HDesign/src/assets/search.svg new file mode 100644 index 000000000..4f33e89c3 --- /dev/null +++ b/HDesign/src/assets/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/HDesign/src/assets/svg.d.ts b/HDesign/src/assets/svg.d.ts new file mode 100644 index 000000000..2db81e756 --- /dev/null +++ b/HDesign/src/assets/svg.d.ts @@ -0,0 +1,6 @@ +declare module '*.svg' { + import type React from 'react'; + + const SVG: React.FC>; + export default SVG; +} diff --git a/HDesign/src/assets/trash.svg b/HDesign/src/assets/trash.svg new file mode 100644 index 000000000..09b228b17 --- /dev/null +++ b/HDesign/src/assets/trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx new file mode 100644 index 000000000..67d4cdb37 --- /dev/null +++ b/HDesign/src/components/BottomSheet/BottomSheet.stories.tsx @@ -0,0 +1,33 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import {useState} from 'react'; + +import Button from '@components/Button/Button'; +import BottomSheet from '@components/BottomSheet/BottomSheet'; + +const meta = { + title: 'Components/BottomSheet', + component: BottomSheet, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: {}, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + render: ({...args}) => { + const [isOpened, setIsOpened] = useState(false); + return ( + <> + + ); +}); + +export default Button; diff --git a/HDesign/src/components/Button/Button.type.ts b/HDesign/src/components/Button/Button.type.ts new file mode 100644 index 000000000..a0402b1dc --- /dev/null +++ b/HDesign/src/components/Button/Button.type.ts @@ -0,0 +1,16 @@ +import {Theme} from '@theme/theme.type'; + +export type ButtonSize = 'small' | 'medium' | 'large'; +export type ButtonVariants = 'primary' | 'secondary' | 'tertiary' | 'destructive' | 'loading'; + +export interface ButtonStyleProps { + variants?: ButtonVariants; + size?: ButtonSize; + theme?: Theme; +} + +export interface ButtonCustomProps {} + +export type ButtonOptionProps = ButtonStyleProps & ButtonCustomProps; + +export type ButtonProps = React.ComponentProps<'button'> & ButtonOptionProps; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx new file mode 100644 index 000000000..c7125d4d8 --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.stories.tsx @@ -0,0 +1,51 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; + +const meta = { + title: 'Components/DragHandleItem', + component: DragHandleItem, + tags: ['autodocs'], + parameters: {}, + argTypes: { + backgroundColor: { + description: '', + control: {type: 'select'}, + options: ['white', 'gray', 'darkGray', 'black', 'primary', 'onPrimary', 'secondary', 'onSecondary'], + }, + hasDragHandler: { + description: '드래그할 수 있는 핸들러(불주사 자국)를 켜고 끌 수 있습니다.', + control: {type: 'boolean'}, + }, + prefix: { + description: '', + control: {type: 'text'}, + }, + suffix: { + description: '', + control: {type: 'text'}, + }, + isFixed: { + description: '컴포넌트가 고정되어 있는지 여부를 나타냅니다.', + control: {type: 'boolean'}, + }, + }, + args: { + backgroundColor: 'white', + hasDragHandler: true, + prefix: '뽕쟁이족발', + suffix: '398,000 원', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; + +export const FixedItem: Story = { + args: { + isFixed: true, + }, +}; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts new file mode 100644 index 000000000..b641c5fb3 --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.style.ts @@ -0,0 +1,20 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export const dragHandleItemStyle = (theme: Theme, hasDragHandle: boolean, backgroundColor: ColorKeys) => + css({ + display: 'flex', + justifyContent: 'space-between', + padding: hasDragHandle ? '0.5rem 1rem 0.5rem 0.5rem' : '0.5rem 1rem', + borderRadius: '0.75rem', + backgroundColor: theme.colors[backgroundColor], + }); + +export const dragHandlerStyle = css({ + display: 'flex', + gap: '0.25rem', + width: '100%', +}); diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.tsx b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx new file mode 100644 index 000000000..9acf38084 --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.tsx @@ -0,0 +1,44 @@ +/** @jsxImportSource @emotion/react */ +import Icon from '@components/Icon/Icon'; +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; +import IsFixedIcon from '@components/IsFixedIcon/IsFixedIcon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import IconButton from '../IconButton/IconButton'; + +import {dragHandleItemStyle, dragHandlerStyle} from './DragHandleItem.style'; +import {DragHandleItemProps} from './DragHandleItem.type'; + +export const DragHandleItem = ({ + hasDragHandler = false, + backgroundColor = 'white', + isFixed = false, + prefix, + suffix, + ...htmlProps +}: DragHandleItemProps) => { + const {theme} = useTheme(); + + // TODO: (@toari) : 사람 수 많을 때 UX writing 처리 + return ( +
+
+ {hasDragHandler && ( + + + + )} + + {prefix} + + {isFixed && } + {suffix} + + +
+
+ ); +}; +export default DragHandleItem; diff --git a/HDesign/src/components/DragHandleItem/DragHandleItem.type.ts b/HDesign/src/components/DragHandleItem/DragHandleItem.type.ts new file mode 100644 index 000000000..fc0a1f520 --- /dev/null +++ b/HDesign/src/components/DragHandleItem/DragHandleItem.type.ts @@ -0,0 +1,19 @@ +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export interface DragHandleItemStyleProps { + theme?: Theme; + backgroundColor?: ColorKeys; +} + +export interface DragHandleItemCustomProps { + hasDragHandler?: boolean; + prefix?: string; + suffix?: string; + isFixed?: boolean; +} + +export type DragHandleItemOptionProps = DragHandleItemStyleProps & DragHandleItemCustomProps; + +export type DragHandleItemProps = React.ComponentProps<'div'> & DragHandleItemOptionProps; diff --git a/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx new file mode 100644 index 000000000..46c3db8a2 --- /dev/null +++ b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.stories.tsx @@ -0,0 +1,90 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import DragHandleItemContainer from '@components/DragHandleItemContainer/DragHandleItemContainer'; +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; + +const meta = { + title: 'Components/DragHandleItemContainer', + component: DragHandleItemContainer, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + topLeftText: { + description: '', + control: {type: 'text'}, + }, + topRightText: { + description: '', + control: {type: 'text'}, + }, + bottomLeftText: { + description: '', + control: {type: 'text'}, + }, + bottomRightText: { + description: '', + control: {type: 'text'}, + }, + backgroundColor: { + description: '', + control: { + type: 'select', + options: [ + 'white', + 'black', + 'primary', + 'onPrimary', + 'secondary', + 'onSecondary', + 'tertiary', + 'onTertiary', + 'gray', + 'darkGray', + 'grayContainer', + 'lightGrayContainer', + 'error', + 'errorContainer', + 'onErrorContainer', + 'warn', + 'complete', + ], + }, + }, + }, + args: { + topLeftText: '으아니차', + topRightText: '8명', + bottomLeftText: '총액', + bottomRightText: '214,000 원', + onTopLeftTextClick: () => alert('왼쪽 위'), + onTopRightTextClick: () => alert('오른쪽 위'), + onBottomLeftTextClick: () => alert('왼쪽 아래'), + onBottomRightTextClick: () => alert('오른쪽 아래'), + backgroundColor: 'white', + children: ( + <> + + + + ), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts new file mode 100644 index 000000000..b5bab9422 --- /dev/null +++ b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.style.ts @@ -0,0 +1,34 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export const containerStyle = (theme: Theme, backgroundColor: ColorKeys) => + css({ + display: 'flex', + flexDirection: 'column', + gap: '0.5rem', + padding: '0.5rem', + borderRadius: '0.75rem', + backgroundColor: theme.colors[backgroundColor], + }); + +export const topRightTextStyle = (theme: Theme) => + css({ + position: 'relative', + cursor: 'pointer', + + '&::after': { + position: 'absolute', + bottom: '0.125rem', + left: 0, + + width: '100%', + height: '0.03125rem', + + backgroundColor: theme.colors.gray, + + content: "''", + }, + }); diff --git a/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.tsx b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.tsx new file mode 100644 index 000000000..a95bfb5de --- /dev/null +++ b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.tsx @@ -0,0 +1,47 @@ +/** @jsxImportSource @emotion/react */ +import {useTheme} from '@theme/HDesignProvider'; + +import Text from '../Text/Text'; +import Flex from '../Flex/Flex'; + +import {containerStyle, topRightTextStyle} from './DragHandleItemContainer.style'; +import {DragHandleItemContainerProps} from './DragHandleItemContainer.type'; + +export const DragHandleItemContainer: React.FC = ({ + topLeftText, + bottomLeftText, + topRightText, + bottomRightText, + onTopLeftTextClick, + onBottomLeftTextClick, + onTopRightTextClick, + onBottomRightTextClick, + backgroundColor = 'white', + children, + ...htmlProps +}: DragHandleItemContainerProps) => { + const {theme} = useTheme(); + + return ( +
+ + + {topLeftText} + + + {topRightText} + + + {children} + + + {bottomLeftText} + + + {bottomRightText} + + +
+ ); +}; +export default DragHandleItemContainer; diff --git a/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.type.ts b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.type.ts new file mode 100644 index 000000000..1bf1129e4 --- /dev/null +++ b/HDesign/src/components/DragHandleItemContainer/DragHandleItemContainer.type.ts @@ -0,0 +1,20 @@ +import {ColorKeys} from '@token/colors'; + +export interface DragHandleItemContainerStyleProps { + backgroundColor?: ColorKeys; +} + +export interface DragHandleItemContainerCustomProps { + topLeftText?: string; + onTopLeftTextClick?: () => void; + bottomLeftText?: string; + onBottomLeftTextClick?: () => void; + topRightText?: string; + onTopRightTextClick?: () => void; + bottomRightText?: string; + onBottomRightTextClick?: () => void; +} + +export type DragHandleItemContainerOptionProps = DragHandleItemContainerStyleProps & DragHandleItemContainerCustomProps; + +export type DragHandleItemContainerProps = React.ComponentProps<'div'> & DragHandleItemContainerOptionProps; diff --git a/HDesign/src/components/EditableItem/EditableItem.Input.style.ts b/HDesign/src/components/EditableItem/EditableItem.Input.style.ts new file mode 100644 index 000000000..eadff482e --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.Input.style.ts @@ -0,0 +1,84 @@ +import {css} from '@emotion/react'; + +import {TextSize} from '@components/Text/Text.type'; +import {WithTheme} from '@type/withTheme'; + +import TYPOGRAPHY from '@token/typography'; + +type UnderlineProps = { + hasFocus: boolean; + hasError: boolean; +}; + +type InputSizeStyleProps = { + textSize: TextSize; +}; + +type InputStyleProps = InputSizeStyleProps; + +export const inputWrapperStyle = css({ + display: 'inline-block', +}); + +export const inputStyle = ({theme, textSize}: WithTheme) => [ + inputSizeStyle({textSize}), + inputBaseStyle({theme}), +]; + +const inputSizeStyle = ({textSize}: InputSizeStyleProps) => { + const style = { + head: css(TYPOGRAPHY.head), + title: css(TYPOGRAPHY.title), + subTitle: css(TYPOGRAPHY.subTitle), + bodyBold: css(TYPOGRAPHY.bodyBold), + body: css(TYPOGRAPHY.body), + smallBodyBold: css(TYPOGRAPHY.smallBodyBold), + smallBody: css(TYPOGRAPHY.smallBody), + captionBold: css(TYPOGRAPHY.captionBold), + caption: css(TYPOGRAPHY.caption), + tiny: css(TYPOGRAPHY.tiny), + }; + + return [style[textSize]]; +}; + +const inputBaseStyle = ({theme}: WithTheme) => + css({ + border: 'none', + outline: 'none', + paddingBottom: '0.125rem', + + color: theme.colors.black, + + '&:placeholder': { + color: theme.colors.darkGray, + }, + }); + +export const editingContainerStyle = css({ + opacity: 0, + whiteSpace: 'pre', + position: 'absolute', + pointerEvents: 'none', + padding: 0, + margin: 0, +}); + +export const underlineStyle = ({theme, hasFocus, hasError}: WithTheme) => + css({ + position: 'relative', + display: 'inline-block', + + '&::after': { + content: '""', + position: 'absolute', + + left: 0, + right: 0, + bottom: 0, + height: '0.125rem', + backgroundColor: hasFocus ? theme.colors.primary : hasError ? theme.colors.error : 'transparent', + transition: 'background-color 0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }, + }); diff --git a/HDesign/src/components/EditableItem/EditableItem.Input.tsx b/HDesign/src/components/EditableItem/EditableItem.Input.tsx new file mode 100644 index 000000000..c0a08bc0e --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.Input.tsx @@ -0,0 +1,54 @@ +/** @jsxImportSource @emotion/react */ +import {forwardRef, useEffect, useImperativeHandle, useRef} from 'react'; + +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; +import IsFixedIcon from '@components/IsFixedIcon/IsFixedIcon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {editingContainerStyle, inputStyle, inputWrapperStyle, underlineStyle} from './EditableItem.Input.style'; +import {InputProps} from './EditableItem.Input.type'; +import useEditableItemInput from './useEditableItemInput'; + +export const EditableItemInput = forwardRef(function Input( + {isFixed = false, textSize = 'body', hasError = false, readOnly = false, ...htmlProps}, + ref, +) { + const {theme} = useTheme(); + const inputRef = useRef(null); + const shadowRef = useRef(null); + const {hasFocus} = useEditableItemInput({inputRef}); + useImperativeHandle(ref, () => inputRef.current!); + + useEffect(() => { + if (shadowRef.current && inputRef.current) { + inputRef.current.style.width = `${shadowRef.current.offsetWidth}px`; + } + }, [htmlProps.value]); + + return ( +
+ +
+ {htmlProps.value || htmlProps.placeholder} +
+ {isFixed && } +
+ +
+
+
+ ); +}); + +export default EditableItemInput; diff --git a/HDesign/src/components/EditableItem/EditableItem.Input.type.ts b/HDesign/src/components/EditableItem/EditableItem.Input.type.ts new file mode 100644 index 000000000..8fdd3d64a --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.Input.type.ts @@ -0,0 +1,22 @@ +import {TextSize} from '@components/Text/Text.type'; + +import {Theme} from '@theme/theme.type'; + +export interface InputStyleProps { + hasError?: boolean; + textSize?: TextSize; +} + +export interface InputCustomProps { + isFixed?: boolean; + value: string | number; + readOnly?: boolean; +} + +export interface InputStylePropsWithTheme extends InputStyleProps { + theme: Theme; +} + +export type InputOptionProps = InputStyleProps & InputCustomProps; + +export type InputProps = React.ComponentProps<'input'> & InputOptionProps; diff --git a/HDesign/src/components/EditableItem/EditableItem.context.tsx b/HDesign/src/components/EditableItem/EditableItem.context.tsx new file mode 100644 index 000000000..a2aeef4bc --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.context.tsx @@ -0,0 +1,23 @@ +/** @jsxImportSource @emotion/react */ +import {createContext, PropsWithChildren, useContext, useState} from 'react'; + +interface EditableItemContextProps { + hasAnyFocus: boolean; + setHasAnyFocus: React.Dispatch>; +} + +const EditableItemContext = createContext(null); + +export const useEditableItemContext = () => { + const context = useContext(EditableItemContext); + if (!context) { + throw new Error('useEditableItemContext must be used within an EditableItemProvider'); + } + return context; +}; + +export const EditableItemProvider: React.FC = ({children}: React.PropsWithChildren) => { + const [hasAnyFocus, setHasAnyFocus] = useState(false); + + return {children}; +}; diff --git a/HDesign/src/components/EditableItem/EditableItem.input.stories.tsx b/HDesign/src/components/EditableItem/EditableItem.input.stories.tsx new file mode 100644 index 000000000..370d07c89 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.input.stories.tsx @@ -0,0 +1,45 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import EditableItemInput from '@components/EditableItem/EditableItem.Input'; + +import EditableItem from './EditableItem'; +import {EditableItemProvider} from './EditableItem.context'; + +const meta = { + title: 'Components/EditableItemInput', + component: EditableItemInput, + tags: ['autodocs'], + parameters: {}, + argTypes: { + textSize: { + description: '', + control: {type: 'select'}, + }, + hasError: { + description: '', + control: {type: 'boolean'}, + }, + }, + args: { + placeholder: '지출 내역', + textSize: 'body', + hasError: false, + autoFocus: true, + value: '값', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + render: ({...args}) => { + return ( + + + + ); + }, +}; diff --git a/HDesign/src/components/EditableItem/EditableItem.stories.tsx b/HDesign/src/components/EditableItem/EditableItem.stories.tsx new file mode 100644 index 000000000..38406727e --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.stories.tsx @@ -0,0 +1,276 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import {useState} from 'react'; + +import EditableItem from '@components/EditableItem/EditableItem'; +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; + +const meta = { + title: 'Components/EditableItem', + component: EditableItem, + tags: ['autodocs'], + parameters: {}, + argTypes: { + backgroundColor: { + description: '', + control: {type: 'select'}, + }, + }, + args: { + backgroundColor: 'lightGrayContainer', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + render: ({...args}) => { + const [value, setValue] = useState(''); + const [value2, setValue2] = useState(''); + + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + setValue(e.target.value)} + placeholder="지출 내역" + textSize="bodyBold" + > + + setValue2(e.target.value)} + placeholder="0" + type="number" + style={{textAlign: 'right'}} + > + + + + ); + }, +}; + +export const WithLabel: Story = { + render: ({...args}) => { + const [value, setValue] = useState(''); + const [value2, setValue2] = useState(''); + + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + setValue(e.target.value)} + placeholder="지출 내역" + textSize="bodyBold" + > + + setValue2(e.target.value)} + placeholder="0" + type="number" + style={{textAlign: 'right'}} + > + + + + ); + }, +}; + +export const WithLabelAndIsFixedIcon: Story = { + render: ({...args}) => { + const [value, setValue] = useState(''); + const [value2, setValue2] = useState(''); + + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + setValue(e.target.value)} + placeholder="지출 내역" + textSize="bodyBold" + > + + setValue2(e.target.value)} + isFixed={true} + placeholder="0" + type="number" + style={{textAlign: 'right'}} + > + + + + ); + }, +}; + +export const WithLabels: Story = { + render: ({...args}) => { + const [value, setValue] = useState(''); + const [value2, setValue2] = useState(''); + + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + setValue(e.target.value)} + placeholder="지출 내역" + textSize="bodyBold" + > + + setValue2(e.target.value)} + placeholder="0" + type="number" + style={{textAlign: 'right'}} + > + + + + ); + }, +}; + +export const ReadOnly: Story = { + render: ({...args}) => { + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + + + + + + + ); + }, +}; + +export const ReadOnlyWithIsFixedIcon: Story = { + render: ({...args}) => { + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + + + + + + + ); + }, +}; + +export const ListView: Story = { + render: ({...args}) => { + const LENGTH = 5; + const [valueList, setValueList] = useState(new Array(LENGTH).fill('')); + const [valueList2, setValueList2] = useState(new Array(LENGTH).fill('')); + + const handleValueListChange = (index: number, newValue: string) => { + const updatedList = [...valueList]; + updatedList[index] = newValue; + setValueList(updatedList); + }; + + const handleValueList2Change = (index: number, newValue: string) => { + const updatedList = [...valueList2]; + updatedList[index] = newValue; + setValueList2(updatedList); + }; + + return ( + console.log('focus')} + onBlur={() => console.log('blur')} + > + + {valueList.map((value, index) => ( + + handleValueListChange(index, e.target.value)} + placeholder="지출 내역" + textSize="bodyBold" + > + + handleValueList2Change(index, e.target.value)} + placeholder="0" + type="number" + style={{textAlign: 'right'}} + > + + + + ))} + + + ); + }, +}; diff --git a/HDesign/src/components/EditableItem/EditableItem.style.ts b/HDesign/src/components/EditableItem/EditableItem.style.ts new file mode 100644 index 000000000..97142f2d8 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.style.ts @@ -0,0 +1,21 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export const editableItemStyle = (theme: Theme, backgroundColor: ColorKeys) => + css({ + display: 'flex', + justifyContent: 'space-between', + padding: '0.5rem 1rem', + borderRadius: '0.75rem', + backgroundColor: theme.colors[backgroundColor], + }); + +export const labelTextStyle = (theme: Theme, side: 'prefix' | 'suffix') => + css({ + color: theme.colors.gray, + paddingLeft: side === 'prefix' ? '0.375rem' : 0, + paddingRight: side === 'suffix' ? '0.375rem' : 0, + }); diff --git a/HDesign/src/components/EditableItem/EditableItem.tsx b/HDesign/src/components/EditableItem/EditableItem.tsx new file mode 100644 index 000000000..f8b9ca434 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.tsx @@ -0,0 +1,54 @@ +/** @jsxImportSource @emotion/react */ +import Text from '@components/Text/Text'; +import Flex from '@components/Flex/Flex'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {editableItemStyle, labelTextStyle} from './EditableItem.style'; +import EditableItemInput from './EditableItem.Input'; +import {EditableItemProps} from './EditableItem.type'; +import {EditableItemProvider} from './EditableItem.context'; +import useEditableItem from './useEditableItem'; + +const EditableItemBase = ({ + onInputFocus, + onInputBlur, + prefixLabelText, + suffixLabelText, + backgroundColor = 'white', + children, + ...htmlProps +}: EditableItemProps) => { + const {theme} = useTheme(); + + useEditableItem({onInputFocus, onInputBlur}); + + return ( + + + + {prefixLabelText} + + + {suffixLabelText} + + + +
+ {children} +
+
+ ); +}; + +export const EditableItem = (props: EditableItemProps) => { + return ( + + + + ); +}; + +EditableItem.Input = EditableItemInput; + +export default EditableItem; diff --git a/HDesign/src/components/EditableItem/EditableItem.type.ts b/HDesign/src/components/EditableItem/EditableItem.type.ts new file mode 100644 index 000000000..a56835855 --- /dev/null +++ b/HDesign/src/components/EditableItem/EditableItem.type.ts @@ -0,0 +1,22 @@ +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export interface EditableItemStyleProps { + backgroundColor?: ColorKeys; +} + +export interface EditableItemCustomProps { + onInputFocus?: () => void; + onInputBlur?: () => void; + prefixLabelText?: string; + suffixLabelText?: string; +} + +export interface EditableItemStylePropsWithTheme extends EditableItemStyleProps { + theme: Theme; +} + +export type EditableItemOptionProps = EditableItemStyleProps & EditableItemCustomProps; + +export type EditableItemProps = React.ComponentProps<'div'> & EditableItemOptionProps; diff --git a/HDesign/src/components/EditableItem/useEditableItem.ts b/HDesign/src/components/EditableItem/useEditableItem.ts new file mode 100644 index 000000000..86880deb6 --- /dev/null +++ b/HDesign/src/components/EditableItem/useEditableItem.ts @@ -0,0 +1,23 @@ +import {useEffect} from 'react'; + +import {useEditableItemContext} from './EditableItem.context'; + +interface UseEditableItemProps { + onInputFocus?: () => void; + onInputBlur?: () => void; +} + +const useEditableItem = ({onInputFocus, onInputBlur}: UseEditableItemProps) => { + const {hasAnyFocus} = useEditableItemContext(); + + useEffect(() => { + if (hasAnyFocus && onInputFocus) { + onInputFocus(); + } + if (!hasAnyFocus && onInputBlur) { + onInputBlur(); + } + }, [hasAnyFocus, onInputFocus, onInputBlur]); +}; + +export default useEditableItem; diff --git a/HDesign/src/components/EditableItem/useEditableItemInput.ts b/HDesign/src/components/EditableItem/useEditableItemInput.ts new file mode 100644 index 000000000..3253ad0ea --- /dev/null +++ b/HDesign/src/components/EditableItem/useEditableItemInput.ts @@ -0,0 +1,46 @@ +import {useCallback, useEffect, useState} from 'react'; + +import {useEditableItemContext} from './EditableItem.context'; + +interface UseEditableItemInputProps { + inputRef: React.RefObject; +} + +const useEditableItemInput = ({inputRef}: UseEditableItemInputProps) => { + const [hasFocus, setHasFocus] = useState(false); + const {setHasAnyFocus} = useEditableItemContext(); + + const handleFocus = useCallback(() => { + setHasFocus(true); + setHasAnyFocus(true); + }, [setHasAnyFocus]); + + const handleBlur = useCallback(() => { + setHasFocus(false); + setHasAnyFocus(false); + }, [setHasAnyFocus]); + + useEffect(() => { + const input = inputRef.current; + + if (input) { + input.addEventListener('focus', handleFocus); + input.addEventListener('blur', handleBlur); + + return () => { + input.removeEventListener('focus', handleFocus); + input.removeEventListener('blur', handleBlur); + }; + } + }, [handleFocus, handleBlur, inputRef]); + + useEffect(() => { + if (document.activeElement === inputRef.current) { + handleFocus(); + } + }, [handleFocus, inputRef]); + + return {hasFocus}; +}; + +export default useEditableItemInput; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx new file mode 100644 index 000000000..ccf8e28de --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.stories.tsx @@ -0,0 +1,29 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import ExpenseList from '@components/ExpenseList/ExpenseList'; + +const meta = { + title: 'Components/ExpenseList', + component: ExpenseList, + tags: ['autodocs'], + argTypes: { + expenseList: { + description: '', + }, + }, + args: { + expenseList: [ + {name: '소하', price: 2000}, + {name: '토다리', price: 2000}, + {name: '웨디', price: 1080}, + {name: '쿠키', price: 3020}, + ], + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.style.ts b/HDesign/src/components/ExpenseList/ExpenseList.style.ts new file mode 100644 index 000000000..8dbd227aa --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.style.ts @@ -0,0 +1,29 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const expenseItemStyle = () => + css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + height: '2.5rem', + padding: '0.5rem 1rem', + }); + +export const expenseItemLeftStyle = () => + css({ + display: 'flex', + alignItems: 'center', + gap: '1rem', + }); + +export const expenseListStyle = (theme: Theme) => + css({ + width: '100%', + backgroundColor: theme.colors.white, + padding: '0.5rem 0', + borderRadius: '1rem', + height: '100%', + }); diff --git a/HDesign/src/components/ExpenseList/ExpenseList.tsx b/HDesign/src/components/ExpenseList/ExpenseList.tsx new file mode 100644 index 000000000..1f57810e5 --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.tsx @@ -0,0 +1,37 @@ +/** @jsxImportSource @emotion/react */ + +import Text from '@components/Text/Text'; +import Icon from '@components/Icon/Icon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {ExpenseItemProps, ExpenseListProps} from './ExpenseList.type'; +import {expenseItemStyle, expenseListStyle, expenseItemLeftStyle} from './ExpenseList.style'; + +// TODO: (@soha) 따로 파일 분리할까 고민중.. 여기서만 사용할 것 같긴 한데.. 흠 +// TODO: (@todari) : 추후 클릭 시 상호작용이 생기면 iconButton으로 변경할 수 있음 +function ExpenseItem({name, price, ...buttonProps}: ExpenseItemProps) { + const {theme} = useTheme(); + return ( + + ); +} + +function ExpenseList({expenseList = []}: ExpenseListProps) { + const {theme} = useTheme(); + return ( +
+ {expenseList.map(({name, price}, index: number) => ( + + ))} +
+ ); +} + +export default ExpenseList; diff --git a/HDesign/src/components/ExpenseList/ExpenseList.type.ts b/HDesign/src/components/ExpenseList/ExpenseList.type.ts new file mode 100644 index 000000000..939cd2f68 --- /dev/null +++ b/HDesign/src/components/ExpenseList/ExpenseList.type.ts @@ -0,0 +1,10 @@ +export interface ExpenseItemCustomProps { + name: string; + price: number; +} + +export type ExpenseItemProps = React.ComponentProps<'button'> & ExpenseItemCustomProps; + +export type ExpenseListProps = { + expenseList: ExpenseItemProps[]; +}; diff --git a/HDesign/src/components/FixedButton/FixedButton.stories.tsx b/HDesign/src/components/FixedButton/FixedButton.stories.tsx new file mode 100644 index 000000000..47485f851 --- /dev/null +++ b/HDesign/src/components/FixedButton/FixedButton.stories.tsx @@ -0,0 +1,46 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import FixedButton from '@components/FixedButton/FixedButton'; + +const meta = { + title: 'Components/FixedButton', + component: FixedButton, + tags: ['autodocs'], + parameters: {}, + argTypes: { + variants: { + description: '', + control: {type: 'select'}, + options: ['', 'primary', 'secondary', 'tertiary', 'loading'], + }, + disabled: { + description: '', + control: {type: 'boolean'}, + }, + onDeleteClick: { + description: '', + control: {type: 'select'}, + options: [undefined, () => alert('delete')], + }, + }, + args: { + variants: 'primary', + disabled: false, + children: 'button', + onDeleteClick: () => alert('delete'), + }, + decorators: [ + Story => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/FixedButton/FixedButton.style.ts b/HDesign/src/components/FixedButton/FixedButton.style.ts new file mode 100644 index 000000000..2e774918d --- /dev/null +++ b/HDesign/src/components/FixedButton/FixedButton.style.ts @@ -0,0 +1,127 @@ +import {css} from '@emotion/react'; + +import {ButtonVariants} from '@components/Button/Button.type'; +import {FixedButtonStyleProps} from '@components/FixedButton/FixedButton.type'; + +import {Theme} from '@theme/theme.type'; + +import {setDarker, setLighter} from '@utils/colors'; + +export const fixedButtonContainerStyle = (theme: Theme) => + css({ + display: 'flex', + position: 'fixed', + maxWidth: '768px', + inset: 'auto 0 0', + margin: '0 auto', + backgroundColor: theme.colors.white, + boxSizing: 'border-box', + }); + +export const buttonContainerStyle = css({ + display: 'flex', + gap: '1rem', + margin: '1rem 1rem 2rem 1rem', + width: '100%', +}); + +const getHoverAndActiveBackground = (color: string) => + css({ + ':not(:disabled)': { + '&:hover': { + backgroundColor: setLighter(color, 0.15), + }, + '&:active': { + backgroundColor: setDarker(color, 0.15), + }, + }, + }); + +export const deleteButtonStyle = (theme: Theme) => [ + css({ + display: 'flex', + justifyContent: 'center', + padding: '0.875rem 1rem', + borderRadius: '1.25rem', + backgroundColor: theme.colors.error, + color: theme.colors.white, + + fontFamily: 'Pretendard', + fontSize: '1rem', + fontWeight: '700', + lineHeight: '1', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }), + getHoverAndActiveBackground(theme.colors.error), +]; + +export const fixedButtonStyle = (props: Required) => { + return [getFixedButtonDefaultStyle(props.theme), getFixedButtonVariantsStyle(props.variants, props.theme)]; +}; + +const getFixedButtonDefaultStyle = (theme: Theme) => + css({ + display: 'flex', + justifyContent: 'center', + padding: '1rem 1.5rem', + borderRadius: '1rem', + width: '100%', + + fontFamily: 'Pretendard', + fontSize: '1.25rem', + fontWeight: '700', + lineHeight: '1', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + + '&:disabled': { + backgroundColor: theme.colors.tertiary, + color: theme.colors.onPrimary, + cursor: 'default', + }, + }); + +const getFixedButtonVariantsStyle = (variants: ButtonVariants, theme: Theme) => { + const style = { + primary: [ + css({ + backgroundColor: theme.colors.primary, + color: theme.colors.onPrimary, + }), + getHoverAndActiveBackground(theme.colors.primary), + ], + secondary: [ + css({ + backgroundColor: theme.colors.secondary, + color: theme.colors.onSecondary, + }), + getHoverAndActiveBackground(theme.colors.secondary), + ], + tertiary: [ + css({ + backgroundColor: theme.colors.tertiary, + color: theme.colors.onTertiary, + }), + getHoverAndActiveBackground(theme.colors.tertiary), + ], + destructive: [ + css({ + backgroundColor: theme.colors.error, + color: theme.colors.onPrimary, + }), + getHoverAndActiveBackground(theme.colors.error), + ], + loading: [ + css({ + backgroundColor: theme.colors.tertiary, + color: theme.colors.onTertiary, + }), + getHoverAndActiveBackground(theme.colors.tertiary), + ], + }; + + return style[variants]; +}; diff --git a/HDesign/src/components/FixedButton/FixedButton.tsx b/HDesign/src/components/FixedButton/FixedButton.tsx new file mode 100644 index 000000000..4430016d6 --- /dev/null +++ b/HDesign/src/components/FixedButton/FixedButton.tsx @@ -0,0 +1,48 @@ +/** @jsxImportSource @emotion/react */ +import {forwardRef} from 'react'; +import Lottie from 'lottie-react'; + +import { + fixedButtonContainerStyle, + fixedButtonStyle, + buttonContainerStyle, +} from '@components/FixedButton/FixedButton.style'; +import {FixedButtonProps} from '@components/FixedButton/FixedButton.type'; +import IconButton from '@components/IconButton/IconButton'; +import Icon from '@components/Icon/Icon'; + +import loadingAnimation from '@assets/loadingAnimation.json'; + +import {useTheme} from '@theme/HDesignProvider'; + +export const FixedButton: React.FC = forwardRef(function Button( + {variants = 'primary', onDeleteClick, disabled, children, ...htmlProps}: FixedButtonProps, + ref, +) { + const {theme} = useTheme(); + return ( +
+
+ {onDeleteClick && ( + + + + )} + +
+
+ ); +}); + +export default FixedButton; diff --git a/HDesign/src/components/FixedButton/FixedButton.type.ts b/HDesign/src/components/FixedButton/FixedButton.type.ts new file mode 100644 index 000000000..1e8c55144 --- /dev/null +++ b/HDesign/src/components/FixedButton/FixedButton.type.ts @@ -0,0 +1,16 @@ +import {ButtonVariants} from '@components/Button/Button.type'; + +import {Theme} from '@theme/theme.type'; + +export interface FixedButtonStyleProps { + variants?: ButtonVariants; + theme?: Theme; +} + +export interface ButtonCustomProps { + onDeleteClick?: () => void; +} + +export type FixedButtonOptionProps = FixedButtonStyleProps & ButtonCustomProps; + +export type FixedButtonProps = React.ComponentProps<'button'> & FixedButtonOptionProps; diff --git a/HDesign/src/components/Flex/Flex.style.ts b/HDesign/src/components/Flex/Flex.style.ts new file mode 100644 index 000000000..672cf2dd6 --- /dev/null +++ b/HDesign/src/components/Flex/Flex.style.ts @@ -0,0 +1,49 @@ +import {css} from '@emotion/react'; + +import {changeCamelCaseToKebabCase} from '@utils/changeCamelCaseToKebabCase'; + +import {FlexDirectionStrictType, FlexProps} from './Flex.type'; + +export const flexStyle = ({ + justifyContent = 'flexStart', + alignItems = 'stretch', + flexDirection = 'row', + gap = '0', + padding = '0', + paddingInline = '0', + margin = '0', + width = 'auto', + height = 'auto', + minHeight, + backgroundColor, + theme, + ...rest +}: FlexProps) => + css({ + display: 'flex', + justifyContent: changeCamelCaseToKebabCase(justifyContent), + alignItems: changeCamelCaseToKebabCase(alignItems), + // TODO: (@weadie) as를 사용하지 않으면 방법이 없음. css의 flexDirection속성은 string을 받지 않고 명확한 속성명(ex row-reverse)를 받고 싶어함. 다만 as를 사용해도 된다고 생각한 근거는 케밥함수가 FlexDirectionType에 명시된 모든 타입을 정확하게 변환하며, 받는 문자열이 FlexDirectionType에 제한되기 때문. + flexDirection: changeCamelCaseToKebabCase(flexDirection) as FlexDirectionStrictType, + gap, + padding, + paddingInline, + margin, + width, + height, + minHeight, + ...rest, + + backgroundColor: (() => { + switch (backgroundColor) { + case 'white': + return theme?.colors.white; + case 'gray': + return theme?.colors.grayContainer; + case 'lightGray': + return theme?.colors.lightGrayContainer; + default: + return 'none'; + } + })(), + }); diff --git a/HDesign/src/components/Flex/Flex.tsx b/HDesign/src/components/Flex/Flex.tsx new file mode 100644 index 000000000..26ce953f7 --- /dev/null +++ b/HDesign/src/components/Flex/Flex.tsx @@ -0,0 +1,17 @@ +/** @jsxImportSource @emotion/react */ +import {css} from '@emotion/react'; + +import {StrictPropsWithChildren} from '@type/strictPropsWithChildren'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {FlexProps} from './Flex.type'; +import {flexStyle} from './Flex.style'; + +// TODO: (@weadie) 지정된 프롭 말고 다른 프롭도 가져올 수 있게 하자. +function Flex({children, ...props}: StrictPropsWithChildren) { + const {theme} = useTheme(); + return
{children}
; +} + +export default Flex; diff --git a/HDesign/src/components/Flex/Flex.type.ts b/HDesign/src/components/Flex/Flex.type.ts new file mode 100644 index 000000000..e70fb4c21 --- /dev/null +++ b/HDesign/src/components/Flex/Flex.type.ts @@ -0,0 +1,20 @@ +import {Theme} from '@theme/theme.type'; + +export type FlexDirectionType = 'row' | 'column' | 'rowReverse' | 'columnReverse'; +export type FlexDirectionStrictType = 'row' | 'column' | 'row-reverse' | 'column-reverse'; +export type FlexBackgroundColor = 'gray' | 'white' | 'lightGray'; + +export interface FlexProps { + justifyContent?: 'flexStart' | 'center' | 'flexEnd' | 'spaceBetween' | 'spaceAround' | 'spaceEvenly'; + alignItems?: 'flexStart' | 'center' | 'flexEnd' | 'stretch' | 'baseline'; + flexDirection?: FlexDirectionType; + gap?: string; + padding?: string; + paddingInline?: string; + margin?: string; + width?: string; + height?: string; + backgroundColor?: FlexBackgroundColor; + theme?: Theme; + minHeight?: string; +} diff --git a/HDesign/src/components/Icon/Icon.stories.tsx b/HDesign/src/components/Icon/Icon.stories.tsx new file mode 100644 index 000000000..3d2ef4aae --- /dev/null +++ b/HDesign/src/components/Icon/Icon.stories.tsx @@ -0,0 +1,28 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Icon from '@components/Icon/Icon'; + +const meta = { + title: 'Components/Icon', + component: Icon, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + iconType: { + description: '', + control: {type: 'select'}, + options: ['inputDelete', 'buljusa', 'rightChevron', 'search', 'confirm', 'error', 'trash'], + }, + }, + args: { + iconType: 'rightChevron', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Icon/Icon.style.ts b/HDesign/src/components/Icon/Icon.style.ts new file mode 100644 index 000000000..b19601da6 --- /dev/null +++ b/HDesign/src/components/Icon/Icon.style.ts @@ -0,0 +1,38 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +import {IconColor, IconStylePropsWithTheme, IconType} from './Icon.type'; + +const ICON_DEFAULT_COLOR: Record = { + inputDelete: 'gray', + buljusa: 'gray', + rightChevron: 'gray', + search: 'gray', + confirm: 'complete', + error: 'warn', + trash: 'white', +}; + +export const iconStyle = ({iconType, theme, iconColor}: IconStylePropsWithTheme) => { + return [ + css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }), + getIconColor({iconType, theme, iconColor}), + ]; +}; + +const getIconColor = ({iconType, theme, iconColor}: IconStylePropsWithTheme) => { + if (iconColor) { + return css({ + color: theme.colors[iconColor as ColorKeys], + }); + } else { + return css({color: theme.colors[ICON_DEFAULT_COLOR[iconType]]}); + } +}; diff --git a/HDesign/src/components/Icon/Icon.tsx b/HDesign/src/components/Icon/Icon.tsx new file mode 100644 index 000000000..13d8e7835 --- /dev/null +++ b/HDesign/src/components/Icon/Icon.tsx @@ -0,0 +1,29 @@ +/** @jsxImportSource @emotion/react */ + +import {IconProps} from '@components/Icon/Icon.type'; +import {InputDelete, Buljusa, RightChevron, Search, Trash, Confirm, Error} from '@assets'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {iconStyle} from './Icon.style'; + +const ICON = { + inputDelete: , + buljusa: , + rightChevron: , + search: , + error: , + confirm: , + trash: , +}; + +export const Icon: React.FC = ({iconColor, iconType, ...htmlProps}: IconProps) => { + const {theme} = useTheme(); + return ( +
+ {ICON[iconType]} +
+ ); +}; + +export default Icon; diff --git a/HDesign/src/components/Icon/Icon.type.ts b/HDesign/src/components/Icon/Icon.type.ts new file mode 100644 index 000000000..57fc25cfb --- /dev/null +++ b/HDesign/src/components/Icon/Icon.type.ts @@ -0,0 +1,21 @@ +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export type IconType = 'inputDelete' | 'buljusa' | 'rightChevron' | 'search' | 'error' | 'confirm' | 'trash'; +export type IconColor = ColorKeys; + +export interface IconStyleProps { + iconColor?: IconColor; + iconType: IconType; +} + +export interface IconStylePropsWithTheme extends IconStyleProps { + theme: Theme; +} + +export interface IconCustomProps {} + +export type IconOptionProps = IconStyleProps & IconCustomProps; + +export type IconProps = React.ComponentProps<'div'> & IconOptionProps; diff --git a/HDesign/src/components/IconButton/IconButton.stories.tsx b/HDesign/src/components/IconButton/IconButton.stories.tsx new file mode 100644 index 000000000..6cc2b5f3d --- /dev/null +++ b/HDesign/src/components/IconButton/IconButton.stories.tsx @@ -0,0 +1,51 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import IconButton from '@components/IconButton/IconButton'; +import Icon from '@components/Icon/Icon'; + +const meta = { + title: 'Components/IconButton', + component: IconButton, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + size: { + description: '', + control: {type: 'select'}, + options: ['large', 'medium', 'small'], + }, + variants: { + description: '', + control: {type: 'select'}, + options: ['none', 'primary', 'secondary', 'tertiary', 'destructive'], + }, + children: { + description: '', + control: {type: 'select'}, + // TODO: (@todari) : Icon의 색상을 variants에 의해 자동으로 변경해 줄 수 있는 로직 추가 + options: [ + , + , + , + , + , + , + , + ], + }, + }, + args: { + size: 'medium', + variants: 'destructive', + children: , + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/IconButton/IconButton.style.ts b/HDesign/src/components/IconButton/IconButton.style.ts new file mode 100644 index 000000000..53036eb68 --- /dev/null +++ b/HDesign/src/components/IconButton/IconButton.style.ts @@ -0,0 +1,102 @@ +/** @jsxImportSource @emotion/react */ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {setDarker, setLighter} from '@utils/colors'; + +import { + IconButtonSize, + IconButtonStyleProps, + IconButtonStylePropsWithTheme, + IconButtonVariants, +} from './IconButton.type'; + +export const iconButtonStyle = ({theme, size = 'large', variants}: IconButtonStylePropsWithTheme) => { + if (variants === 'none') { + return 'none'; + } + return [getIconButtonBase(theme), getIconButtonSize(size), getIconButtonVariants({variants, theme})]; +}; + +const getHoverAndActiveBackground = (color: string) => + css({ + ':not(:disabled)': { + '&:hover': { + backgroundColor: setLighter(color, 0.15), + }, + '&:active': { + backgroundColor: setDarker(color, 0.15), + }, + }, + }); + +const getIconButtonBase = (theme: Theme) => + css({ + display: 'flex', + justifyContent: 'center', + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + whiteSpace: 'nowrap', + + '&:disabled': { + backgroundColor: theme.colors.tertiary, + color: theme.colors.onPrimary, + cursor: 'default', + }, + }); + +const getIconButtonSize = (size: IconButtonSize) => { + const style = { + small: css({ + padding: '0.5rem', + borderRadius: '0.75rem', + }), + medium: css({ + padding: '0.75rem', + borderRadius: '1rem', + }), + large: css({ + padding: '0.875rem', + borderRadius: '1.125rem', + }), + }; + + return style[size]; +}; + +const getIconButtonVariants = ({variants, theme}: IconButtonStylePropsWithTheme) => { + const style = { + none: [css({})], + primary: [ + css({ + backgroundColor: theme.colors.primary, + color: theme.colors.onPrimary, + }), + getHoverAndActiveBackground(theme.colors.primary), + ], + secondary: [ + css({ + backgroundColor: theme.colors.secondary, + color: theme.colors.onSecondary, + }), + getHoverAndActiveBackground(theme.colors.secondary), + ], + tertiary: [ + css({ + backgroundColor: theme.colors.tertiary, + color: theme.colors.onTertiary, + }), + getHoverAndActiveBackground(theme.colors.tertiary), + ], + destructive: [ + css({ + backgroundColor: theme.colors.error, + color: theme.colors.onPrimary, + }), + getHoverAndActiveBackground(theme.colors.error), + ], + }; + + return style[variants]; +}; diff --git a/HDesign/src/components/IconButton/IconButton.tsx b/HDesign/src/components/IconButton/IconButton.tsx new file mode 100644 index 000000000..bc704db67 --- /dev/null +++ b/HDesign/src/components/IconButton/IconButton.tsx @@ -0,0 +1,22 @@ +/** @jsxImportSource @emotion/react */ +import {forwardRef} from 'react'; + +import {IconButtonProps} from '@components/IconButton/IconButton.type'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {iconButtonStyle} from './IconButton.style'; + +export const IconButton: React.FC = forwardRef(function Button( + {size, variants, children, ...htmlProps}: IconButtonProps, + ref, +) { + const {theme} = useTheme(); + return ( + + ); +}); + +export default IconButton; diff --git a/HDesign/src/components/IconButton/IconButton.type.ts b/HDesign/src/components/IconButton/IconButton.type.ts new file mode 100644 index 000000000..de891e0ba --- /dev/null +++ b/HDesign/src/components/IconButton/IconButton.type.ts @@ -0,0 +1,19 @@ +import {Theme} from '@theme/theme.type'; + +export type IconButtonSize = 'large' | 'medium' | 'small'; +export type IconButtonVariants = 'none' | 'primary' | 'secondary' | 'tertiary' | 'destructive'; + +export interface IconButtonStyleProps { + size?: IconButtonSize; + variants: IconButtonVariants; +} + +export interface IconButtonStylePropsWithTheme extends IconButtonStyleProps { + theme: Theme; +} + +export interface IconButtonCustomProps {} + +export type IconButtonOptionProps = IconButtonStyleProps & IconButtonCustomProps; + +export type IconButtonProps = React.ComponentProps<'button'> & IconButtonOptionProps; diff --git a/HDesign/src/components/Input/Input.stories.tsx b/HDesign/src/components/Input/Input.stories.tsx new file mode 100644 index 000000000..dc46e022f --- /dev/null +++ b/HDesign/src/components/Input/Input.stories.tsx @@ -0,0 +1,56 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import React, {useEffect, useState} from 'react'; + +import Input from '@components/Input/Input'; +import Flex from '@components/Flex/Flex'; +import Button from '@components/Button/Button'; + +const meta = { + title: 'Components/Input', + component: Input, + tags: ['autodocs'], + argTypes: { + inputType: { + // TODO: (@cookie) 스토리북 라디오버튼 보이도록 설정해야 함 + control: {type: 'radio'}, + }, + }, + args: { + placeholder: 'placeholder', + autoFocus: true, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + render: ({...args}) => { + const regex = /^[ㄱ-ㅎ가-힣]*$/; + const [value, setValue] = useState(''); + const [isError, setIsError] = useState(false); + + const handleChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + if (regex.test(newValue)) { + setValue(newValue); + setIsError(false); + } else { + setIsError(true); + } + }; + + const changeRandomValue = () => { + setValue('외부에서 값 변경됨'); + }; + + return ( +
+ + +
+ ); + }, +}; diff --git a/HDesign/src/components/Input/Input.style.ts b/HDesign/src/components/Input/Input.style.ts new file mode 100644 index 000000000..a9ddff89d --- /dev/null +++ b/HDesign/src/components/Input/Input.style.ts @@ -0,0 +1,56 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {InputType} from './Input.type'; + +const getBackgroundColorStyle = (theme: Theme, inputType: InputType = 'input') => { + switch (inputType) { + case 'input': + return theme.colors.lightGrayContainer; + + case 'search': + return theme.colors.white; + + default: + return theme.colors.lightGrayContainer; + } +}; + +const getBorderStyle = (isFocus: boolean, theme: Theme, isError?: boolean) => + isError ? `0 0 0 1px ${theme.colors.error} inset` : isFocus ? `0 0 0 1px ${theme.colors.primary} inset` : 'none'; + +export const inputBoxStyle = ( + theme: Theme, + inputType: InputType = 'input', + isFocus: boolean, + isError: boolean | undefined, +) => + css({ + display: 'flex', + justifyContent: 'space-between', + gap: '1rem', + padding: '0.75rem 1rem', + borderRadius: '1rem', + backgroundColor: getBackgroundColorStyle(theme, inputType), + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + + boxSizing: 'border-box', + boxShadow: getBorderStyle(isFocus, theme, isError), + }); + +export const inputStyle = (theme: Theme) => + css( + { + display: 'flex', + width: '100%', + color: theme.colors.black, + + '&:placeholder': { + color: theme.colors.gray, + }, + }, + theme.typography.body, + ); diff --git a/HDesign/src/components/Input/Input.tsx b/HDesign/src/components/Input/Input.tsx new file mode 100644 index 000000000..37945e434 --- /dev/null +++ b/HDesign/src/components/Input/Input.tsx @@ -0,0 +1,51 @@ +/** @jsxImportSource @emotion/react */ +import React, {forwardRef, useImperativeHandle, useRef} from 'react'; + +import IconButton from '@components/IconButton/IconButton'; +import {InputProps} from '@components/Input/Input.type'; +import {inputBoxStyle, inputStyle} from '@components/Input/Input.style'; +import {useInput} from '@components/Input/useInput'; +import Icon from '@components/Icon/Icon'; + +import {useTheme} from '@theme/HDesignProvider'; + +export const Input: React.FC = forwardRef(function Input( + {value: propsValue, onChange, onFocus, onBlur, inputType, isError, placeholder, autoFocus, ...htmlProps}: InputProps, + ref, +) { + const {theme} = useTheme(); + const inputRef = useRef(null); + const {value, handleChange, hasFocus, handleClickDelete, handleBlur, handleFocus, handleKeyDown} = useInput({ + propsValue, + onChange, + onBlur, + onFocus, + inputRef, + autoFocus, + }); + useImperativeHandle(ref, () => inputRef.current!); + + return ( +
+ + {value && hasFocus && ( + + + + )} +
+ ); +}); + +export default Input; diff --git a/HDesign/src/components/Input/Input.type.ts b/HDesign/src/components/Input/Input.type.ts new file mode 100644 index 000000000..2cfdfcd4a --- /dev/null +++ b/HDesign/src/components/Input/Input.type.ts @@ -0,0 +1,16 @@ +import {Theme} from '@theme/theme.type'; + +export interface InputStyleProps { + theme?: Theme; +} + +export type InputType = 'input' | 'search'; + +export interface InputCustomProps { + inputType?: InputType; + isError?: boolean; +} + +export type InputOptionProps = InputStyleProps & InputCustomProps; + +export type InputProps = React.ComponentProps<'input'> & InputOptionProps; diff --git a/HDesign/src/components/Input/useInput.ts b/HDesign/src/components/Input/useInput.ts new file mode 100644 index 000000000..a9e531a07 --- /dev/null +++ b/HDesign/src/components/Input/useInput.ts @@ -0,0 +1,71 @@ +import {RefObject, useEffect, useState} from 'react'; + +interface UseInputProps { + propsValue: T; + onChange?: (e: React.ChangeEvent) => void; + onFocus?: (event: React.FocusEvent) => void; + onBlur?: (event: React.FocusEvent) => void; + inputRef: RefObject; + autoFocus?: boolean; +} + +export const useInput = ({propsValue, onChange, onBlur, onFocus, autoFocus, inputRef}: UseInputProps) => { + const [value, setValue] = useState(propsValue); + const [hasFocus, setHasFocus] = useState(inputRef.current === document.activeElement); + + useEffect(() => { + if (autoFocus && inputRef.current) { + inputRef.current.focus(); + setHasFocus(true); + } + }, [autoFocus, inputRef]); + + useEffect(() => { + setValue(propsValue); + }, [propsValue, value]); + + const handleClickDelete = (event: React.MouseEvent) => { + event.preventDefault(); + setValue('' as T); + if (onChange) { + onChange({target: {value: ''}} as React.ChangeEvent); + } + if (inputRef.current) { + inputRef.current.focus(); + } + }; + + const handleChange = (e: React.ChangeEvent) => { + setValue(e.target.value as T); + if (onChange) { + onChange(e); + } + }; + + const handleBlur = (e: React.FocusEvent) => { + setHasFocus(false); + if (onBlur) { + onBlur(e); + } + }; + + const handleFocus = (e: React.FocusEvent) => { + setHasFocus(true); + if (onFocus) { + onFocus(e); + } + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.nativeEvent.isComposing) return; + + if (event.key === 'Enter' || event.key === 'Escape') { + setHasFocus(false); + if (inputRef.current) { + inputRef.current.blur(); + } + } + }; + + return {value, handleChange, hasFocus, handleClickDelete, handleBlur, handleFocus, handleKeyDown}; +}; diff --git a/HDesign/src/components/IsFixedIcon/IsFixedIcon.style.ts b/HDesign/src/components/IsFixedIcon/IsFixedIcon.style.ts new file mode 100644 index 000000000..6ba001e05 --- /dev/null +++ b/HDesign/src/components/IsFixedIcon/IsFixedIcon.style.ts @@ -0,0 +1,9 @@ +import {css} from '@emotion/react'; + +import {WithTheme} from '@type/withTheme'; + +export const isFixedIconStyle = ({theme}: WithTheme) => + css({ + color: theme.colors.error, + paddingRight: '0.25rem', + }); diff --git a/HDesign/src/components/IsFixedIcon/IsFixedIcon.tsx b/HDesign/src/components/IsFixedIcon/IsFixedIcon.tsx new file mode 100644 index 000000000..a7b62d959 --- /dev/null +++ b/HDesign/src/components/IsFixedIcon/IsFixedIcon.tsx @@ -0,0 +1,13 @@ +/** @jsxImportSource @emotion/react */ + +import {useTheme} from '@theme/HDesignProvider'; + +import {isFixedIconStyle} from './IsFixedIcon.style'; + +const IsFixedIcon = () => { + const {theme} = useTheme(); + + return
*
; +}; + +export default IsFixedIcon; diff --git a/HDesign/src/components/LabelGroupInput/Element.tsx b/HDesign/src/components/LabelGroupInput/Element.tsx new file mode 100644 index 000000000..5ffd852bd --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/Element.tsx @@ -0,0 +1,63 @@ +/** @jsxImportSource @emotion/react */ + +import {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react'; + +import Input from '../Input/Input'; + +import {ElementProps} from './Element.type'; +import {useGroupInputContext} from './GroupInputContext'; + +const Element: React.FC = forwardRef(function Element( + {elementKey, value: propsValue, onChange, onBlur, onFocus, isError, autoFocus, ...htmlProps}: ElementProps, + + ref, +) { + useImperativeHandle(ref, () => inputRef.current!); + const inputRef = useRef(null); + const {setHasAnyFocus, values, setValues, errors, setErrors} = useGroupInputContext(); + + useEffect(() => { + setValues({...values, [elementKey]: `${propsValue}`}); + }, [propsValue]); + + const handleChange = (e: React.ChangeEvent) => { + const newValue = e.target.value; + setValues({...values, [elementKey]: newValue}); + if (onChange) { + onChange(e); + } + }; + + useEffect(() => { + setErrors({...errors, [elementKey]: isError ?? false}); + }, [isError]); + + const handleBlur = (e: React.FocusEvent) => { + setHasAnyFocus(false); + if (onBlur) { + onBlur(e); + } + }; + + const handleFocus = (e: React.FocusEvent) => { + setHasAnyFocus(true); + if (onFocus) { + onFocus(e); + } + }; + + return ( + + ); +}); + +export default Element; diff --git a/HDesign/src/components/LabelGroupInput/Element.type.ts b/HDesign/src/components/LabelGroupInput/Element.type.ts new file mode 100644 index 000000000..2ec2ef9ed --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/Element.type.ts @@ -0,0 +1,10 @@ +export interface ElementStyleProps {} + +export interface ElementCustomProps { + elementKey: string; + isError?: boolean; +} + +export type ElementOptionProps = ElementStyleProps & ElementCustomProps; + +export type ElementProps = React.ComponentProps<'input'> & ElementOptionProps; diff --git a/HDesign/src/components/LabelGroupInput/GroupInputContext.tsx b/HDesign/src/components/LabelGroupInput/GroupInputContext.tsx new file mode 100644 index 000000000..142183e6b --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/GroupInputContext.tsx @@ -0,0 +1,32 @@ +import React, {createContext, PropsWithChildren, useContext, useState} from 'react'; + +interface GroupInputContextProps { + hasAnyFocus: boolean; + setHasAnyFocus: React.Dispatch>; + values: {[key: string]: string}; + setValues: React.Dispatch>; + errors: {[key: string]: boolean}; + setErrors: React.Dispatch>; +} + +const GroupInputContext = createContext(undefined); + +export const useGroupInputContext = () => { + const context = useContext(GroupInputContext); + if (!context) { + throw new Error('useGroupInputContext must be used within an GroupInputProvider'); + } + return context; +}; + +export const GroupInputProvider: React.FC = ({children}: React.PropsWithChildren) => { + const [hasAnyFocus, setHasAnyFocus] = useState(false); + const [values, setValues] = useState<{[key: string]: string}>({}); + const [errors, setErrors] = useState<{[key: string]: boolean}>({}); + + return ( + + {children} + + ); +}; diff --git a/HDesign/src/components/LabelGroupInput/LabelGroupInput.stories.tsx b/HDesign/src/components/LabelGroupInput/LabelGroupInput.stories.tsx new file mode 100644 index 000000000..4eec9634f --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/LabelGroupInput.stories.tsx @@ -0,0 +1,75 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import {useState} from 'react'; + +import LabelGroupInput from '@components/LabelGroupInput/LabelGroupInput'; + +const meta = { + title: 'Components/LabelGroupInput', + component: LabelGroupInput, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + labelText: { + description: 'label에 들어갈 텍스트를 작성', + control: {type: 'text'}, + }, + errorText: { + description: 'error에 들어갈 텍스트를 작성', + control: {type: 'text'}, + }, + }, + args: { + labelText: '지출내역 / 금액', + errorText: 'error가 발생했을 때 나타납니다!', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + render: ({...args}) => { + const [name, setName] = useState(''); + const [price, setPrice] = useState(''); + const [isError, setIsError] = useState(false); + const handleChangeName = (event: React.ChangeEvent) => { + if (event.target.value.length < 4) { + setName(event.target.value); + setIsError(false); + } else { + event.target.value = name; + setIsError(true); + } + }; + const handleChangePrice = (event: React.ChangeEvent) => { + setPrice(event.target.value); + }; + return ( + + handleChangeName(e)} + onBlur={() => console.log('!!!')} + isError={isError} + autoFocus + /> + console.log('!!!')} + isError={false} + autoFocus + /> + + ); + }, +}; diff --git a/HDesign/src/components/LabelGroupInput/LabelGroupInput.style.ts b/HDesign/src/components/LabelGroupInput/LabelGroupInput.style.ts new file mode 100644 index 000000000..8339ef4a4 --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/LabelGroupInput.style.ts @@ -0,0 +1,25 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@/theme/theme.type'; + +export const labelTextStyle = (theme: Theme, hasFocus: boolean, hasValue: boolean) => + css({ + height: '1.125rem', + color: theme.colors.gray, + + opacity: hasFocus || hasValue ? '1' : '0', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }); + +export const errorTextStyle = (theme: Theme, isError: boolean) => + css({ + height: '1.125rem', + color: theme.colors.onErrorContainer, + + opacity: isError ? '1' : '0', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }); diff --git a/HDesign/src/components/LabelGroupInput/LabelGroupInput.tsx b/HDesign/src/components/LabelGroupInput/LabelGroupInput.tsx new file mode 100644 index 000000000..33d1d447d --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/LabelGroupInput.tsx @@ -0,0 +1,48 @@ +/** @jsxImportSource @emotion/react */ + +import Text from '@components/Text/Text'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Flex from '../Flex/Flex'; + +import {LabelGroupInputProps} from './LabelGroupInput.type'; +import {errorTextStyle, labelTextStyle} from './LabelGroupInput.style'; +import Element from './Element'; +import {GroupInputProvider, useGroupInputContext} from './GroupInputContext'; + +const LabelGroupInput: React.FC = ({labelText, errorText, children}: LabelGroupInputProps) => { + const {theme} = useTheme(); + const {hasAnyFocus, values, errors} = useGroupInputContext(); + + const hasAnyValue = !Object.values(values).every(value => value === ''); + const hasAnyError = !Object.values(errors).every(error => !error); + + return ( + + + + {labelText} + + {errorText && ( + + {errorText} + + )} + + + {children} + + + ); +}; + +const LabelGroupInputContainer = (props: LabelGroupInputProps) => ( + + + +); + +LabelGroupInputContainer.Element = Element; + +export default LabelGroupInputContainer; diff --git a/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts b/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts new file mode 100644 index 000000000..8507311b5 --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts @@ -0,0 +1,10 @@ +export interface LabelGroupInputStyleProps {} + +export interface LabelGroupInputCustomProps { + labelText: string; + errorText: string | null; +} + +export type LabelGroupInputOptionProps = LabelGroupInputStyleProps & LabelGroupInputCustomProps; + +export type LabelGroupInputProps = React.ComponentProps<'input'> & LabelGroupInputOptionProps; diff --git a/HDesign/src/components/LabelGroupInput/index.ts b/HDesign/src/components/LabelGroupInput/index.ts new file mode 100644 index 000000000..c31f35eaf --- /dev/null +++ b/HDesign/src/components/LabelGroupInput/index.ts @@ -0,0 +1,3 @@ +import LabelGroupInputContainer from './LabelGroupInput'; + +export {LabelGroupInputContainer as LabelGroupInput}; diff --git a/HDesign/src/components/LabelInput/LabelInput.stories.tsx b/HDesign/src/components/LabelInput/LabelInput.stories.tsx new file mode 100644 index 000000000..a272037a4 --- /dev/null +++ b/HDesign/src/components/LabelInput/LabelInput.stories.tsx @@ -0,0 +1,56 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import {useEffect, useState} from 'react'; + +import LabelInput from '@components/LabelInput/LabelInput'; + +const meta = { + title: 'Components/LabelInput', + component: LabelInput, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + labelText: { + description: 'label에 들어갈 텍스트를 작성', + control: {type: 'text'}, + }, + isError: { + description: '', + control: {type: 'boolean'}, + }, + errorText: { + description: 'error에 들어갈 텍스트를 작성', + control: {type: 'text'}, + }, + }, + args: { + // value: '', + labelText: '이름', + errorText: 'error가 발생했을 때 나타납니다!', + autoFocus: true, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + render: ({...args}) => { + const [value, setValue] = useState(''); + const [isError, setIsError] = useState(false); + const handleChange = (event: React.ChangeEvent) => { + if (event.target.value.length < 4) { + setValue(event.target.value); + setIsError(false); + } else { + event.target.value = value; + setIsError(true); + } + }; + return handleChange(e)} isError={isError} {...args} />; + }, +}; diff --git a/HDesign/src/components/LabelInput/LabelInput.style.ts b/HDesign/src/components/LabelInput/LabelInput.style.ts new file mode 100644 index 000000000..df64636e9 --- /dev/null +++ b/HDesign/src/components/LabelInput/LabelInput.style.ts @@ -0,0 +1,25 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const labelTextStyle = (theme: Theme, hasFocus: boolean, hasValue: boolean) => + css({ + height: '1.125rem', + color: theme.colors.gray, + + opacity: hasFocus || hasValue ? '1' : '0', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }); + +export const errorTextStyle = (theme: Theme, isError: boolean) => + css({ + height: '1.125rem', + color: theme.colors.onErrorContainer, + + opacity: isError ? '1' : '0', + + transition: '0.2s', + transitionTimingFunction: 'cubic-bezier(0.7, 0.62, 0.62, 1.16)', + }); diff --git a/HDesign/src/components/LabelInput/LabelInput.tsx b/HDesign/src/components/LabelInput/LabelInput.tsx new file mode 100644 index 000000000..43f60c220 --- /dev/null +++ b/HDesign/src/components/LabelInput/LabelInput.tsx @@ -0,0 +1,45 @@ +/** @jsxImportSource @emotion/react */ + +import {forwardRef, useImperativeHandle, useRef} from 'react'; + +import Text from '@components/Text/Text'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Input from '../Input/Input'; +import Flex from '../Flex/Flex'; + +import {errorTextStyle, labelTextStyle} from './LabelInput.style'; +import {useLabelInput} from './useLabelInput'; +import {LabelInputProps} from './LabelInput.type'; + +const LabelInput: React.FC = forwardRef(function LabelInput( + {labelText, errorText, isError, ...htmlProps}: LabelInputProps, + ref, +) { + useImperativeHandle(ref, () => inputRef.current!); + + const {theme} = useTheme(); + const inputRef = useRef(null); + const {hasFocus} = useLabelInput({inputRef}); + + return ( + + + + {labelText} + + {errorText && ( + + {errorText} + + )} + + + + + + ); +}); + +export default LabelInput; diff --git a/HDesign/src/components/LabelInput/LabelInput.type.ts b/HDesign/src/components/LabelInput/LabelInput.type.ts new file mode 100644 index 000000000..83e7e9751 --- /dev/null +++ b/HDesign/src/components/LabelInput/LabelInput.type.ts @@ -0,0 +1,12 @@ +export interface LabelInputStyleProps {} + +export interface LabelInputCustomProps { + labelText: string; + errorText: string | null; + isError?: boolean; + autoFocus: boolean; +} + +export type LabelInputOptionProps = LabelInputCustomProps & LabelInputCustomProps; + +export type LabelInputProps = React.ComponentProps<'input'> & LabelInputOptionProps; diff --git a/HDesign/src/components/LabelInput/useLabelInput.ts b/HDesign/src/components/LabelInput/useLabelInput.ts new file mode 100644 index 000000000..e967c5f89 --- /dev/null +++ b/HDesign/src/components/LabelInput/useLabelInput.ts @@ -0,0 +1,26 @@ +import {RefObject, useEffect, useState} from 'react'; + +interface UseLabelInput { + inputRef: RefObject; + autoFocus?: boolean; +} + +export const useLabelInput = ({inputRef, autoFocus}: UseLabelInput) => { + const [hasFocus, setHasFocus] = useState(inputRef.current === document.activeElement); + + useEffect(() => { + setHasFocus(inputRef.current === document.activeElement); + }, []); + + useEffect(() => { + inputRef.current?.addEventListener('focus', () => setHasFocus(true)); + inputRef.current?.addEventListener('blur', () => setHasFocus(false)); + + return () => { + inputRef.current?.removeEventListener('focus', () => setHasFocus(true)); + inputRef.current?.removeEventListener('blur', () => setHasFocus(false)); + }; + }, []); + + return {hasFocus}; +}; diff --git a/HDesign/src/components/ListButton/ListButton.stories.tsx b/HDesign/src/components/ListButton/ListButton.stories.tsx new file mode 100644 index 000000000..27f7744d1 --- /dev/null +++ b/HDesign/src/components/ListButton/ListButton.stories.tsx @@ -0,0 +1,32 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import ListButton from '@components/ListButton/ListButton'; + +const meta = { + title: 'Components/ListButton', + component: ListButton, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + argTypes: { + prefix: { + description: '', + control: {type: 'text'}, + }, + suffix: { + description: '', + control: {type: 'text'}, + }, + }, + args: { + prefix: '전체 참여자', + suffix: '7명', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/ListButton/ListButton.style.ts b/HDesign/src/components/ListButton/ListButton.style.ts new file mode 100644 index 000000000..fcca0ca01 --- /dev/null +++ b/HDesign/src/components/ListButton/ListButton.style.ts @@ -0,0 +1,16 @@ +/** @jsxImportSource @emotion/react */ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const listButtonStyle = (theme: Theme) => + css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + padding: '0.375rem 1rem', + backgroundColor: theme.colors.white, + + boxShadow: `0 1px 0 0 ${theme.colors.grayContainer} inset `, + }); diff --git a/HDesign/src/components/ListButton/ListButton.tsx b/HDesign/src/components/ListButton/ListButton.tsx new file mode 100644 index 000000000..10c417310 --- /dev/null +++ b/HDesign/src/components/ListButton/ListButton.tsx @@ -0,0 +1,36 @@ +/** @jsxImportSource @emotion/react */ +import React, {forwardRef} from 'react'; + +import Text from '@components/Text/Text'; +import IconButton from '@components/IconButton/IconButton'; +import Flex from '@components/Flex/Flex'; +import Icon from '@components/Icon/Icon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {ListButtonProps} from './ListButton.type'; +import {listButtonStyle} from './ListButton.style'; + +export const ListButton: React.FC = forwardRef(function Button( + {prefix, suffix, ...htmlProps}: ListButtonProps, + ref, +) { + const {theme} = useTheme(); + return ( + + ); +}); + +export default ListButton; diff --git a/HDesign/src/components/ListButton/ListButton.type.ts b/HDesign/src/components/ListButton/ListButton.type.ts new file mode 100644 index 000000000..788117870 --- /dev/null +++ b/HDesign/src/components/ListButton/ListButton.type.ts @@ -0,0 +1,10 @@ +export interface ListButtonStyleProps {} + +export interface ListButtonCustomProps { + prefix?: string; + suffix?: string; +} + +export type ListButtonOptionProps = ListButtonStyleProps & ListButtonCustomProps; + +export type ListButtonProps = React.ComponentProps<'button'> & ListButtonOptionProps; diff --git a/HDesign/src/components/Search/Search.stories.tsx b/HDesign/src/components/Search/Search.stories.tsx new file mode 100644 index 000000000..6b5d821cd --- /dev/null +++ b/HDesign/src/components/Search/Search.stories.tsx @@ -0,0 +1,32 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import React from 'react'; + +import Search from '@components/Search/Search'; + +const meta = { + title: 'Components/Search', + component: Search, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + decorators: [ + Story => ( +
+ +
+ ), + ], + args: { + isShowTargetInput: true, + matchItems: ['todari', 'cookie'], + onMatchItemClick: keyword => alert(keyword), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Search/Search.style.ts b/HDesign/src/components/Search/Search.style.ts new file mode 100644 index 000000000..d75e8fe25 --- /dev/null +++ b/HDesign/src/components/Search/Search.style.ts @@ -0,0 +1,42 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const searchStyle = css({ + position: 'relative', + + width: '100%', +}); + +export const searchTermsStyle = (theme: Theme) => + css({ + position: 'absolute', + top: '3.5rem', + zIndex: 1, + + width: '100%', + padding: '0.5rem 1rem', + + borderRadius: '1rem', + + backgroundColor: theme.colors.white, + + boxShadow: '0 0.25rem 0.5rem 0 rgba(0, 0, 0, 0.12)', + }); + +export const searchTermStyle = (theme: Theme) => + css( + { + width: '100%', + padding: '0.5rem', + + color: theme.colors.onTertiary, + + '&:hover': { + borderRadius: '0.5rem', + + backgroundColor: theme.colors.lightGrayContainer, + }, + }, + theme.typography.body, + ); diff --git a/HDesign/src/components/Search/Search.tsx b/HDesign/src/components/Search/Search.tsx new file mode 100644 index 000000000..58c292cc4 --- /dev/null +++ b/HDesign/src/components/Search/Search.tsx @@ -0,0 +1,37 @@ +/** @jsxImportSource @emotion/react */ +import Flex from '@components/Flex/Flex'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {searchStyle, searchTermsStyle, searchTermStyle} from './Search.style'; + +export interface SearchProps { + isShowTargetInput: boolean; + matchItems: string[]; + onMatchItemClick: (term: string) => void; +} + +const Search = ({isShowTargetInput, matchItems, onMatchItemClick, children}: React.PropsWithChildren) => { + const {theme} = useTheme(); + + return ( +
+ {children} + {matchItems.length > 0 && isShowTargetInput && ( +
    + + {matchItems.map((matchItem, index) => ( +
  • + +
  • + ))} +
    +
+ )} +
+ ); +}; + +export default Search; diff --git a/HDesign/src/components/Switch/Switch.stories.tsx b/HDesign/src/components/Switch/Switch.stories.tsx new file mode 100644 index 000000000..a3558754a --- /dev/null +++ b/HDesign/src/components/Switch/Switch.stories.tsx @@ -0,0 +1,35 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Switch from '@components/Switch/Switch'; + +const meta = { + title: 'Components/Switch', + component: Switch, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + value: { + description: '', + control: {type: 'select', options: ['홈', '관리']}, + }, + values: { + description: '', + }, + onChange: { + description: '', + }, + }, + args: { + value: '홈', + values: ['홈', '관리'], + onChange: value => alert(`${value} 선택됨`), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Switch/Switch.style.ts b/HDesign/src/components/Switch/Switch.style.ts new file mode 100644 index 000000000..d88c18748 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.style.ts @@ -0,0 +1,6 @@ +import {css} from '@emotion/react'; + +export const switchContainerStyle = css({ + display: 'flex', + gap: '0.75rem', +}); diff --git a/HDesign/src/components/Switch/Switch.tsx b/HDesign/src/components/Switch/Switch.tsx new file mode 100644 index 000000000..4a1275185 --- /dev/null +++ b/HDesign/src/components/Switch/Switch.tsx @@ -0,0 +1,24 @@ +/** @jsxImportSource @emotion/react */ +import TextButton from '../TextButton/TextButton'; + +import {switchContainerStyle} from './Switch.style'; +import {SwitchProps} from './Switch.type'; + +function Switch({value, values, onChange}: SwitchProps) { + return ( +
+ {values.map((item, index) => ( + onChange(values[index])} + > + {item} + + ))} +
+ ); +} + +export default Switch; diff --git a/HDesign/src/components/Switch/Switch.type.ts b/HDesign/src/components/Switch/Switch.type.ts new file mode 100644 index 000000000..7e0d31d0f --- /dev/null +++ b/HDesign/src/components/Switch/Switch.type.ts @@ -0,0 +1,5 @@ +export interface SwitchProps { + value: string; + values: string[]; + onChange: (value: string) => void; +} diff --git a/HDesign/src/components/Tabs/Tab.tsx b/HDesign/src/components/Tabs/Tab.tsx new file mode 100644 index 000000000..2a79c1b78 --- /dev/null +++ b/HDesign/src/components/Tabs/Tab.tsx @@ -0,0 +1,8 @@ +/** @jsxImportSource @emotion/react */ +import {TabProps} from './Tab.type'; + +const Tab: React.FC = () => { + return <>; +}; + +export default Tab; diff --git a/HDesign/src/components/Tabs/Tab.type.ts b/HDesign/src/components/Tabs/Tab.type.ts new file mode 100644 index 000000000..6b9e4972e --- /dev/null +++ b/HDesign/src/components/Tabs/Tab.type.ts @@ -0,0 +1,16 @@ +import {FlexProps} from '../Flex/Flex.type'; + +export interface TabProps { + label: string; + content: React.ReactNode; +} + +export interface TabsCustomProps { + children: React.ReactElement[]; +} + +export interface TabsStyleProps { + tabsContainerStyle?: FlexProps; +} + +export type TabsProps = TabsCustomProps & TabsStyleProps; diff --git a/HDesign/src/components/Tabs/Tabs.stories.tsx b/HDesign/src/components/Tabs/Tabs.stories.tsx new file mode 100644 index 000000000..a40e60b07 --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.stories.tsx @@ -0,0 +1,31 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import React from 'react'; + +import Tabs from '@components/Tabs/Tabs'; + +import Tab from './Tab'; + +const meta = { + title: 'Components/Tabs', + component: Tabs, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + args: { + children: [ + 없지롱} />, + 있지롱} />, + ], + tabsContainerStyle: { + gap: '0.5rem', + }, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Tabs/Tabs.style.ts b/HDesign/src/components/Tabs/Tabs.style.ts new file mode 100644 index 000000000..3ea38924c --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.style.ts @@ -0,0 +1,53 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const tabListStyle = (theme: Theme) => + css({ + position: 'relative', + + backgroundColor: theme.colors.white, + + cursor: 'pointer', + + WebkitTapHighlightColor: 'transparent', + + '&::after': { + position: 'absolute', + left: 0, + bottom: 0, + zIndex: 1, + + width: '100%', + height: '0.0625rem', + + backgroundColor: theme.colors.gray, + + content: '""', + }, + }); + +export const tabItemStyle = css({ + flex: 1, + + textAlign: 'center', +}); + +export const tabTextStyle = (theme: Theme, selected: boolean) => + css({ + color: selected ? theme.colors.onTertiary : theme.colors.gray, + }); + +export const indicatorStyle = (theme: Theme, leftPosition: string, tabLength: number) => + css({ + position: 'absolute', + left: leftPosition, + bottom: 0, + zIndex: 2, + + width: `calc(100% / ${tabLength})`, + height: '0.125rem', + + backgroundColor: theme.colors.onSecondary, + transition: 'left 0.3s', + }); diff --git a/HDesign/src/components/Tabs/Tabs.tsx b/HDesign/src/components/Tabs/Tabs.tsx new file mode 100644 index 000000000..0245b5ba7 --- /dev/null +++ b/HDesign/src/components/Tabs/Tabs.tsx @@ -0,0 +1,53 @@ +/** @jsxImportSource @emotion/react */ +import React, {useState} from 'react'; +import {css} from '@emotion/react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Text from '../Text/Text'; +import Flex from '../Flex/Flex'; + +import {tabListStyle, indicatorStyle, tabItemStyle, tabTextStyle} from './Tabs.style'; +import {TabsProps} from './Tab.type'; + +const Tabs: React.FC = ({children, tabsContainerStyle}) => { + const {theme} = useTheme(); + const [activeTabIndex, setActiveTabIndex] = useState(0); + + const isActive = (index: number) => activeTabIndex === index; + const tabItemCount = children.length; + + return ( + +
    + + {children.map((tabItem, index) => ( + + ))} +
    + +
+
+ {children[activeTabIndex].props.content} +
+
+ ); +}; + +export default Tabs; diff --git a/HDesign/src/components/Text/Text.stories.tsx b/HDesign/src/components/Text/Text.stories.tsx new file mode 100644 index 000000000..5e5ec2287 --- /dev/null +++ b/HDesign/src/components/Text/Text.stories.tsx @@ -0,0 +1,40 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Text from '@components/Text/Text'; + +const meta = { + title: 'Components/Text', + component: Text, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + size: { + description: '', + control: {type: 'select'}, + options: [ + 'head', + 'title', + 'subTitle', + 'bodyBold', + 'body', + 'smallBodyBold', + 'smallBody', + 'caption', + 'captionBold', + 'tiny', + ], + }, + }, + args: { + size: 'body', + children: 'text', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Text/Text.style.ts b/HDesign/src/components/Text/Text.style.ts new file mode 100644 index 000000000..650260e62 --- /dev/null +++ b/HDesign/src/components/Text/Text.style.ts @@ -0,0 +1,29 @@ +import type {TextStylePropsWithTheme} from './Text.type'; + +import {css} from '@emotion/react'; + +// TODO: (@todari) themeProvider 이용하도록 변경 +import TYPOGRAPHY from '@token/typography'; + +export const getSizeStyling = ({size, textColor, theme}: Required) => { + const style = { + head: css(TYPOGRAPHY.head), + title: css(TYPOGRAPHY.title), + subTitle: css(TYPOGRAPHY.subTitle), + bodyBold: css(TYPOGRAPHY.bodyBold), + body: css(TYPOGRAPHY.body), + smallBodyBold: css(TYPOGRAPHY.smallBodyBold), + smallBody: css(TYPOGRAPHY.smallBody), + captionBold: css(TYPOGRAPHY.captionBold), + caption: css(TYPOGRAPHY.caption), + tiny: css(TYPOGRAPHY.tiny), + }; + + const colorStyle = css({color: theme.colors[textColor]}); + + const baseStyle = css({ + whiteSpace: 'pre-line', + }); + + return [style[size], colorStyle, baseStyle]; +}; diff --git a/HDesign/src/components/Text/Text.tsx b/HDesign/src/components/Text/Text.tsx new file mode 100644 index 000000000..9b7853aa8 --- /dev/null +++ b/HDesign/src/components/Text/Text.tsx @@ -0,0 +1,19 @@ +/** @jsxImportSource @emotion/react */ +import type {TextProps} from '@components/Text/Text.type'; + +import React from 'react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import {getSizeStyling} from './Text.style'; + +const Text: React.FC = ({size = 'body', textColor = 'black', children, ...attributes}: TextProps) => { + const {theme} = useTheme(); + return ( +

+ {children} +

+ ); +}; + +export default Text; diff --git a/HDesign/src/components/Text/Text.type.ts b/HDesign/src/components/Text/Text.type.ts new file mode 100644 index 000000000..157591abf --- /dev/null +++ b/HDesign/src/components/Text/Text.type.ts @@ -0,0 +1,30 @@ +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +export type TextSize = + | 'head' + | 'title' + | 'subTitle' + | 'body' + | 'smallBody' + | 'caption' + | 'tiny' + | 'bodyBold' + | 'smallBodyBold' + | 'captionBold'; + +export interface TextStyleProps { + size?: TextSize; + textColor?: ColorKeys; +} + +export interface TextStylePropsWithTheme extends TextStyleProps { + theme: Theme; +} + +export interface TextCustomProps {} + +export type TextOptionProps = TextStyleProps & TextCustomProps; + +export type TextProps = React.ComponentProps<'p'> & TextOptionProps; diff --git a/HDesign/src/components/TextButton/TextButton.stories.tsx b/HDesign/src/components/TextButton/TextButton.stories.tsx new file mode 100644 index 000000000..9873df3f4 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.stories.tsx @@ -0,0 +1,50 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import TextButton from '@components/TextButton/TextButton'; + +const meta = { + title: 'Components/TextButton', + component: TextButton, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + textSize: { + description: '', + control: {type: 'select'}, + options: [ + 'head', + 'title', + 'subTitle', + 'bodyBold', + 'body', + 'smallBodyBold', + 'smallBody', + 'caption', + 'captionBold', + 'tiny', + ], + }, + textColor: { + description: '', + control: {type: 'select'}, + options: ['black', 'gray'], + }, + children: { + description: '', + control: {type: 'text'}, + }, + }, + args: { + textColor: 'black', + textSize: 'bodyBold', + children: '뒤로가기', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/TextButton/TextButton.style.ts b/HDesign/src/components/TextButton/TextButton.style.ts new file mode 100644 index 000000000..c8d8738fe --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.style.ts @@ -0,0 +1,10 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ColorKeys} from '@token/colors'; + +interface TextButtonStyleProps { + textColor: ColorKeys; + theme: Theme; +} diff --git a/HDesign/src/components/TextButton/TextButton.tsx b/HDesign/src/components/TextButton/TextButton.tsx new file mode 100644 index 000000000..9e73667d5 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.tsx @@ -0,0 +1,25 @@ +/** @jsxImportSource @emotion/react */ +import {forwardRef} from 'react'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Text from '../Text/Text'; + +import {TextButtonProps} from './TextButton.type'; + +export const TextButton: React.FC = forwardRef(function Button( + {textColor, textSize, children, ...htmlProps}: TextButtonProps, + ref, +) { + const {theme} = useTheme(); + + return ( + + ); +}); + +export default TextButton; diff --git a/HDesign/src/components/TextButton/TextButton.type.ts b/HDesign/src/components/TextButton/TextButton.type.ts new file mode 100644 index 000000000..0299d89b9 --- /dev/null +++ b/HDesign/src/components/TextButton/TextButton.type.ts @@ -0,0 +1,15 @@ +import {TextSize} from '../Text/Text.type'; + +export type TextColor = 'black' | 'gray'; + +export interface TextButtonStyleProps { + textColor: TextColor; +} + +export interface TextButtonCustomProps { + textSize: TextSize; +} + +export type TextButtonOptionProps = TextButtonStyleProps & TextButtonCustomProps; + +export type TextButtonProps = React.ComponentProps<'button'> & TextButtonOptionProps; diff --git a/HDesign/src/components/Title/Title.stories.tsx b/HDesign/src/components/Title/Title.stories.tsx new file mode 100644 index 000000000..2c91287b4 --- /dev/null +++ b/HDesign/src/components/Title/Title.stories.tsx @@ -0,0 +1,38 @@ +import type {Meta, StoryObj} from '@storybook/react'; + +import Title from '@components/Title/Title'; + +const meta = { + title: 'Components/Title', + component: Title, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + argTypes: { + title: { + description: '', + control: {type: 'text'}, + }, + description: { + description: '', + control: {type: 'text'}, + }, + price: { + description: '', + control: {type: 'number'}, + }, + }, + args: { + title: '페이지 제목이에요', + description: `이곳에는 페이지 설명이 들어가요. + 페이지에 대한 설명을 자세하게 적어주면 좋아요 :)`, + price: 100000, + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/Title/Title.style.ts b/HDesign/src/components/Title/Title.style.ts new file mode 100644 index 000000000..ab347a214 --- /dev/null +++ b/HDesign/src/components/Title/Title.style.ts @@ -0,0 +1,19 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +export const titleContainerStyle = (theme: Theme) => + css({ + display: 'flex', + flexDirection: 'column', + width: '100%', + gap: '0.5rem', + backgroundColor: theme.colors.white, + padding: '1rem', + }); + +export const priceContainerStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'end', +}); diff --git a/HDesign/src/components/Title/Title.tsx b/HDesign/src/components/Title/Title.tsx new file mode 100644 index 000000000..e17de5e88 --- /dev/null +++ b/HDesign/src/components/Title/Title.tsx @@ -0,0 +1,34 @@ +/** @jsxImportSource @emotion/react */ +import Flex from '@components/Flex/Flex'; +import Text from '@components/Text/Text'; +import {priceContainerStyle, titleContainerStyle} from '@components/Title/Title.style'; +import {TitleProps} from '@components/Title/Title.type'; + +import {useTheme} from '@theme/HDesignProvider'; + +export const Title: React.FC = ({title, description, price}: TitleProps) => { + const {theme} = useTheme(); + return ( +
+ {title} + {description && ( + + {description} + + )} + {price !== undefined && ( +
+ + 전체 지출 금액 + + + {price.toLocaleString('ko-kr')} + + +
+ )} +
+ ); +}; + +export default Title; diff --git a/HDesign/src/components/Title/Title.type.ts b/HDesign/src/components/Title/Title.type.ts new file mode 100644 index 000000000..4b12f23b2 --- /dev/null +++ b/HDesign/src/components/Title/Title.type.ts @@ -0,0 +1,11 @@ +export interface TitleStyleProps {} + +export interface TitleCustomProps { + title: string; + description?: string; + price?: number; +} + +export type TitleOptionProps = TitleStyleProps & TitleCustomProps; + +export type TitleProps = React.ComponentProps<'div'> & TitleOptionProps; diff --git a/HDesign/src/components/Toast/Toast.stories.tsx b/HDesign/src/components/Toast/Toast.stories.tsx new file mode 100644 index 000000000..fd672959c --- /dev/null +++ b/HDesign/src/components/Toast/Toast.stories.tsx @@ -0,0 +1,71 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import Toast from '@components/Toast/Toast'; + +const meta = { + title: 'Components/Toast', + component: Toast, + tags: ['autodocs'], + parameters: { + // layout: 'centered', + }, + args: { + type: 'confirm', + position: 'top', + top: '80px', + message: `서버 오류로 인해 인원을 설정하는데 실패했어요. +두글자면 이렇게 보여요.`, + onUndo: () => alert('되돌리기 버튼이 눌렸습니다. 실행할 로직을 전달해주세요'), + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const ConfirmToast: Story = { + args: { + ...meta.args, + type: 'confirm', + top: '80px', + message: `이 첫번째 토스트 그림자 짙은거 두 개 떠서 그런거임 css 잘못한거 아닙니다. 잘못 없습니다. 스토리북이 잘못한거에요. 저희는 최선을 다했어요.. `, + }, +}; + +export const ConfirmToastWithoutUndo: Story = { + args: { + ...meta.args, + onUndo: undefined, + top: '160px', + }, +}; + +export const ErrorToast: Story = { + args: { + ...meta.args, + top: '240px', + type: 'error', + message: `님 이거 다 작성했는데, 혹시 되돌림? + 되돌릴 수도 있음 ㅇㅇ 굿`, + }, +}; + +export const ErrorToastWithoutUndo: Story = { + args: { + ...meta.args, + top: '320px', + onUndo: undefined, + type: 'error', + }, +}; + +export const NoneToast: Story = { + args: { + ...meta.args, + top: '400px', + onUndo: undefined, + type: 'none', + message: '웨디는 커비의 먹잇감인가요? 그치만 감자는 웨디한테 먹힘 쿠스쿠스 ㅋ', + }, +}; diff --git a/HDesign/src/components/Toast/Toast.style.ts b/HDesign/src/components/Toast/Toast.style.ts new file mode 100644 index 000000000..0496bc722 --- /dev/null +++ b/HDesign/src/components/Toast/Toast.style.ts @@ -0,0 +1,44 @@ +import {css} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; + +import {ToastPosition} from './Toast.type'; + +type ToastMarginStyle = { + position?: ToastPosition; + bottom?: string; + top?: string; +}; + +export const toastMarginStyle = ({position, bottom, top}: ToastMarginStyle) => + css({ + position: 'absolute', + bottom: position === 'bottom' ? `${bottom}` : 'auto', + top: position === 'top' ? `${top}` : 'auto', + left: '50%', + transform: 'translate(-50%)', + + width: '100%', + maxWidth: '48rem', + paddingInline: '0.5rem', + }); + +export const toastStyle = (theme: Theme) => + css({ + width: '100%', + padding: '0.625rem 1rem', + + backgroundColor: theme.colors.gray, + boxShadow: '0 8px 12px rgba(0, 0, 0, 0.16);', + + borderRadius: '1.25rem', + }); + +export const textStyle = (theme: Theme) => + css({ + width: '100%', + + color: theme.colors.white, + + whiteSpace: 'pre-line', + }); diff --git a/HDesign/src/components/Toast/Toast.tsx b/HDesign/src/components/Toast/Toast.tsx new file mode 100644 index 000000000..972ce6220 --- /dev/null +++ b/HDesign/src/components/Toast/Toast.tsx @@ -0,0 +1,73 @@ +/** @jsxImportSource @emotion/react */ +import {createPortal} from 'react-dom'; + +import Text from '@components/Text/Text'; +import Flex from '@components/Flex/Flex'; +import Icon from '@components/Icon/Icon'; + +import {useTheme} from '@theme/HDesignProvider'; + +import Button from '../Button/Button'; + +import {toastStyle, textStyle, toastMarginStyle} from './Toast.style'; +import {ToastProps, ToastType} from './Toast.type'; + +const renderIcon = (type: ToastType) => { + switch (type) { + case 'error': + return ; + + case 'confirm': + return ; + + case 'none': + return null; + + default: + return null; + } +}; + +const Toast = ({ + type = 'confirm', + top = '0px', + bottom = '0px', + isClickToClose = true, + position = 'bottom', + message, + onUndo, + onClose, + ...htmlProps +}: ToastProps) => { + const {theme} = useTheme(); + const styleProps = {position, top, bottom}; + + const handleClickToClose = () => { + if (!isClickToClose || !onClose) return; + + onClose(); + }; + + return createPortal( +
+
+ + + {renderIcon(type)} + + {message} + + + {onUndo && ( + + )} + +
+
, + document.body, + ); +}; + +export default Toast; diff --git a/HDesign/src/components/Toast/Toast.type.ts b/HDesign/src/components/Toast/Toast.type.ts new file mode 100644 index 000000000..12a436c2d --- /dev/null +++ b/HDesign/src/components/Toast/Toast.type.ts @@ -0,0 +1,21 @@ +export type ToastPosition = 'bottom' | 'top'; +export type ToastType = 'error' | 'confirm' | 'none'; + +export interface ToastStyleProps { + bottom?: string; + top?: string; +} + +export interface ToastOptionProps { + position?: ToastPosition; + type?: ToastType; + onUndo?: () => void; + isClickToClose?: boolean; + onClose?: () => void; +} + +export interface ToastRequiredProps { + message: string; +} + +export type ToastProps = React.ComponentProps<'div'> & ToastStyleProps & ToastOptionProps & ToastRequiredProps; diff --git a/HDesign/src/components/Toast/ToastProvider.stories.tsx b/HDesign/src/components/Toast/ToastProvider.stories.tsx new file mode 100644 index 000000000..32c8c6917 --- /dev/null +++ b/HDesign/src/components/Toast/ToastProvider.stories.tsx @@ -0,0 +1,46 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import Button from '../Button/Button'; + +import {ToastProvider, useToast} from './ToastProvider'; + +const meta = { + title: 'Components/ToastProvider', + component: ToastProvider, + tags: ['autodocs'], + decorators: [ + Story => ( + + + + ), + ], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = { + decorators: [ + () => { + const {showToast} = useToast(); + + return ( + + ); + }, + ], +}; diff --git a/HDesign/src/components/Toast/ToastProvider.tsx b/HDesign/src/components/Toast/ToastProvider.tsx new file mode 100644 index 000000000..9201fdc6d --- /dev/null +++ b/HDesign/src/components/Toast/ToastProvider.tsx @@ -0,0 +1,59 @@ +/** @jsxImportSource @emotion/react */ +import {createContext, useCallback, useContext, useEffect, useState} from 'react'; + +import {ToastProps} from './Toast.type'; +import Toast from './Toast'; + +export const ToastContext = createContext(null); + +interface ToastContextProps { + showToast: (args: ShowToast) => void; +} + +type ShowToast = ToastProps & { + showingTime?: number; + isAlwaysOn?: boolean; +}; + +const ToastProvider = ({children}: React.PropsWithChildren) => { + const [currentToast, setCurrentToast] = useState(null); + + const showToast = useCallback(({showingTime = 3000, isAlwaysOn = false, ...toastProps}: ShowToast) => { + setCurrentToast({showingTime, isAlwaysOn, ...toastProps}); + }, []); + + const closeToast = () => { + setCurrentToast(null); + }; + + useEffect(() => { + if (!currentToast) return; + + if (!currentToast.isAlwaysOn) { + const timer = setTimeout(() => { + setCurrentToast(null); + }, currentToast.showingTime); + + return () => clearTimeout(timer); + } + }, [currentToast]); + + return ( + + {currentToast && } + {children} + + ); +}; + +const useToast = () => { + const context = useContext(ToastContext); + + if (!context) { + throw new Error('useToast는 ToastProvider 내에서 사용되어야 합니다.'); + } + + return context; +}; + +export {ToastProvider, useToast}; diff --git a/HDesign/src/components/TopNav/Back.tsx b/HDesign/src/components/TopNav/Back.tsx new file mode 100644 index 000000000..cfb55e24d --- /dev/null +++ b/HDesign/src/components/TopNav/Back.tsx @@ -0,0 +1,17 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; +import {useNavigate} from 'react-router-dom'; + +import TextButton from '@components/TextButton/TextButton'; + +function Back() { + const navigate = useNavigate(); + + return ( + navigate(-1)} textSize="bodyBold" textColor="gray"> + 뒤로가기 + + ); +} + +export default Back; diff --git a/HDesign/src/components/TopNav/TopNav.stories.tsx b/HDesign/src/components/TopNav/TopNav.stories.tsx new file mode 100644 index 000000000..0c96161a5 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.stories.tsx @@ -0,0 +1,50 @@ +/** @jsxImportSource @emotion/react */ +import type {Meta, StoryObj} from '@storybook/react'; + +import React from 'react'; +import {reactRouterParameters, withRouter} from 'storybook-addon-react-router-v6'; + +import TopNav from '@components/TopNav/TopNav'; + +import Switch from '../Switch/Switch'; + +import Back from './Back'; + +const meta = { + title: 'Components/TopNav', + component: TopNav, + tags: ['autodocs'], + decorators: [withRouter], + parameters: { + reactRouter: reactRouterParameters({ + location: { + pathParams: { + eventId: '123123', + }, + }, + routing: {path: '/event/:eventId/home'}, + }), + // layout: 'centered', + }, + argTypes: { + children: { + description: '', + control: {type: 'select'}, + options: ['Back', 'Switch', 'Any'], + mapping: { + Back: , + Switch: console.log(value)} />, + Any:
, + }, + }, + }, + args: { + children: 'Back', + }, +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Playground: Story = {}; diff --git a/HDesign/src/components/TopNav/TopNav.style.ts b/HDesign/src/components/TopNav/TopNav.style.ts new file mode 100644 index 000000000..9ca69c7b0 --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.style.ts @@ -0,0 +1,18 @@ +import {css} from '@emotion/react'; + +export const topNavStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '0 1rem', + width: '100%', +}); + +export const topNavNonStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '0 1rem', + width: '100%', + height: '1.5rem', +}); diff --git a/HDesign/src/components/TopNav/TopNav.tsx b/HDesign/src/components/TopNav/TopNav.tsx new file mode 100644 index 000000000..643cd5e3b --- /dev/null +++ b/HDesign/src/components/TopNav/TopNav.tsx @@ -0,0 +1,20 @@ +/** @jsxImportSource @emotion/react */ +import React from 'react'; + +import Switch from '@components/Switch/Switch'; + +import {topNavNonStyle, topNavStyle} from './TopNav.style'; +import Back from './Back'; + +const TopNav: React.FC = ({children}) => { + const hasBack = React.Children.toArray(children).some(child => React.isValidElement(child) && child.type === Back); + const hasSwitch = React.Children.toArray(children).some( + child => React.isValidElement(child) && child.type === Switch, + ); + + const isExistNav = hasBack || hasSwitch; + + return
{children}
; +}; + +export default TopNav; diff --git a/HDesign/src/index.tsx b/HDesign/src/index.tsx new file mode 100644 index 000000000..656690951 --- /dev/null +++ b/HDesign/src/index.tsx @@ -0,0 +1,62 @@ +import BottomSheet from '@components/BottomSheet/BottomSheet'; +import Button from '@components/Button/Button'; +import DragHandleItem from '@components/DragHandleItem/DragHandleItem'; +import DragHandleItemContainer from '@components/DragHandleItemContainer/DragHandleItemContainer'; +import EditableItem from '@components/EditableItem/EditableItem'; +import ExpenseList from '@components/ExpenseList/ExpenseList'; +import FixedButton from '@components/FixedButton/FixedButton'; +import Flex from '@components/Flex/Flex'; +import Icon from '@components/Icon/Icon'; +import IconButton from '@components/IconButton/IconButton'; +import Input from '@components/Input/Input'; +import LabelInput from '@components/LabelInput/LabelInput'; +import ListButton from '@components/ListButton/ListButton'; +import LabelGroupInput from '@components/LabelGroupInput/LabelGroupInput'; +import Search from '@components/Search/Search'; +import Switch from '@components/Switch/Switch'; +import Tab from '@components/Tabs/Tab'; +import Tabs from '@components/Tabs/Tabs'; +import Text from '@components/Text/Text'; +import TextButton from '@components/TextButton/TextButton'; +import Title from '@components/Title/Title'; +import Toast from '@components/Toast/Toast'; +import Back from '@components/TopNav/Back'; +import TopNav from '@components/TopNav/TopNav'; +import {ToastProvider, useToast} from '@components/Toast/ToastProvider'; + +import {MainLayout} from '@layouts/MainLayout'; +import {ContentLayout} from '@layouts/ContentLayout'; + +import {HDesignProvider} from '@theme/HDesignProvider'; + +export { + BottomSheet, + Button, + DragHandleItem, + DragHandleItemContainer, + EditableItem, + ExpenseList, + FixedButton, + Flex, + Icon, + IconButton, + Input, + LabelInput, + ListButton, + LabelGroupInput, + Search, + Switch, + Tab, + Tabs, + Text, + TextButton, + Title, + Toast, + TopNav, + Back, + MainLayout, + ContentLayout, + ToastProvider, + useToast, + HDesignProvider, +}; diff --git a/HDesign/src/layouts/ContentLayout.tsx b/HDesign/src/layouts/ContentLayout.tsx new file mode 100644 index 000000000..757a580ec --- /dev/null +++ b/HDesign/src/layouts/ContentLayout.tsx @@ -0,0 +1,25 @@ +import {PropsWithChildren} from 'react'; + +import {Flex} from '..'; + +type ContentLayoutBackground = 'white' | 'gray'; + +interface ContentLayoutProps extends PropsWithChildren { + backgroundColor?: ContentLayoutBackground; +} + +export function ContentLayout({backgroundColor, children}: ContentLayoutProps) { + return ( + + {children} + + ); +} diff --git a/HDesign/src/layouts/MainLayout.tsx b/HDesign/src/layouts/MainLayout.tsx new file mode 100644 index 000000000..22012fde8 --- /dev/null +++ b/HDesign/src/layouts/MainLayout.tsx @@ -0,0 +1,26 @@ +import {PropsWithChildren} from 'react'; + +import {Flex} from '..'; + +type MainLayoutBackground = 'white' | 'gray' | 'lightGray'; + +interface MainLayoutProps extends PropsWithChildren { + backgroundColor?: MainLayoutBackground; +} + +export function MainLayout({backgroundColor, children}: MainLayoutProps) { + return ( + + {children} + + ); +} diff --git a/HDesign/src/theme/GlobalStyle.ts b/HDesign/src/theme/GlobalStyle.ts new file mode 100644 index 000000000..f1b7b699b --- /dev/null +++ b/HDesign/src/theme/GlobalStyle.ts @@ -0,0 +1,123 @@ +import {css} from '@emotion/react'; + +export const GlobalStyle = css` + *:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) { + all: unset; + display: revert; + } + + /* Preferred box-sizing value */ + *, + *::before, + *::after { + box-sizing: border-box; + } + + /* Fix mobile Safari increase font-size on landscape mode */ + html { + -moz-text-size-adjust: none; + -webkit-text-size-adjust: none; + text-size-adjust: none; + } + + /* Reapply the pointer cursor for anchor tags */ + a, + button { + cursor: revert; + line-height: 0; + } + + button:disabled { + cursor: default; + } + + /* Remove list styles (bullets/numbers) */ + ol, + ul, + menu, + summary { + list-style: none; + } + + /* Removes spacing between cells in tables */ + table { + border-collapse: collapse; + } + + /* Safari - solving issue when using user-select:none on the text input doesn't working */ + input, + textarea { + -webkit-user-select: auto; + } + + /* Revert the 'white-space' property for textarea elements on Safari */ + textarea { + white-space: revert; + } + + /* Minimum style to allow to style meter element */ + meter { + -webkit-appearance: revert; + appearance: revert; + } + + /* Preformatted text - use only for this feature */ + :where(pre) { + all: revert; + box-sizing: border-box; + } + + /* Fix the feature of 'hidden' attribute. + display: revert; revert to element instead of attribute */ + :where([hidden]) { + display: none; + } + + /* Revert for bug in Chromium browsers + - Fix for the content editable attribute will work properly. + - webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element */ + :where([contenteditable]:not([contenteditable='false'])) { + -moz-user-modify: read-write; + -webkit-user-modify: read-write; + overflow-wrap: break-word; + -webkit-line-break: after-white-space; + -webkit-user-select: auto; + } + + /* Apply back the draggable feature - exist only in Chromium and Safari */ + :where([draggable='true']) { + -webkit-user-drag: element; + } + + /* Revert Modal native behavior */ + :where(dialog:modal) { + all: revert; + box-sizing: border-box; + } + + /* Remove details summary webkit styles */ + ::-webkit-details-marker { + display: none; + } + + /* Chrome, Safari, Edge, Opera */ + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + /* Firefox */ + input[type='number'] { + -moz-appearance: textfield; + } + + #root { + display: flex; + justify-content: center; + } + + button { + cursor: pointer; + } +`; diff --git a/HDesign/src/theme/HDesignProvider.tsx b/HDesign/src/theme/HDesignProvider.tsx new file mode 100644 index 000000000..6c7c571a3 --- /dev/null +++ b/HDesign/src/theme/HDesignProvider.tsx @@ -0,0 +1,37 @@ +import React, {createContext, useContext, useState, ReactNode} from 'react'; +import {Global} from '@emotion/react'; + +import {Theme} from '@theme/theme.type'; +import {GlobalStyle} from '@theme/GlobalStyle'; + +import {COLORS} from '@token/colors'; +import {TYPOGRAPHY} from '@token/typography'; + +interface ThemeContextProps { + theme: Theme; +} + +const defaultTheme: Theme = { + colors: COLORS, + typography: TYPOGRAPHY, +}; + +const ThemeContext = createContext(undefined); + +export const HDesignProvider: React.FC<{children: ReactNode}> = ({children}) => { + const [theme, _] = useState(defaultTheme); + return ( + + + {children} + + ); +}; + +export const useTheme = (): ThemeContextProps => { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within a HDesignProvider'); + } + return context; +}; diff --git a/HDesign/src/theme/theme.type.ts b/HDesign/src/theme/theme.type.ts new file mode 100644 index 000000000..dffd961f0 --- /dev/null +++ b/HDesign/src/theme/theme.type.ts @@ -0,0 +1,7 @@ +import {ColorTokens} from '@token/colors'; +import {TypographyTokens} from '@token/typography'; + +export interface Theme { + colors: ColorTokens; + typography: TypographyTokens; +} diff --git a/HDesign/src/token/colors.ts b/HDesign/src/token/colors.ts new file mode 100644 index 000000000..3dccdf2d3 --- /dev/null +++ b/HDesign/src/token/colors.ts @@ -0,0 +1,109 @@ +const PRIMITIVE_COLORS = { + white: '#FFFFFF', + purple: { + 50: '#f4e8ff', + 100: '#e0c7fe', + 200: '#cba0fe', + 300: '#b575ff', + 400: '#a350fd', + 500: '#8f2bf3', + 600: '#8425ec', + 700: '#7519e3', + 800: '#6712db', + 900: '#5100cd', + }, + pink: { + 50: '#ffe1ff', + 100: '#feafd9', + 200: '#ff75bf', + 300: '#fc28a1', + 400: '#f60087', + 500: '#f2006d', + 600: '#e1006a', + 700: '#ca0065', + 800: '#b30062', + 900: '#8b005b', + }, + yellow: { + 50: '#fdffe9', + 100: '#f7fdc5', + 200: '#f0fb9d', + 300: '#e8f972', + 400: '#ecff59', + 500: '#e5fb31', + 600: '#daeb2e', + 700: '#c9d323', + 800: '#b9bb17', + 900: '#9e9305', + }, + green: { + 50: '#f4ffe8', + 100: '#e4ffc6', + 200: '#d1ff9f', + 300: '#bfff75', + 400: '#b0fd51', + 500: '#a4f932', + 600: '#9de728', + 700: '#90cf18', + 800: '#85b704', + 900: '#748f00', + }, + gray: { + 50: '#F9F8FD', + 100: '#F1F0F5', + 200: '#E7E6EB', + 300: '#D6D5DA', + 400: '#B2B1B6', + 500: '#929195', + 600: '#6A696D', + 700: '#56555A', + 800: '#38373B', + 900: '#18171B', + }, +}; + +type Color = string; + +export type ColorKeys = + | 'white' + | 'black' + | 'primary' + | 'onPrimary' + | 'secondary' + | 'onSecondary' + | 'tertiary' + | 'onTertiary' + | 'gray' + | 'darkGray' + | 'grayContainer' + | 'lightGrayContainer' + | 'error' + | 'errorContainer' + | 'onErrorContainer' + | 'warn' + | 'complete'; +export type ColorTokens = Record; + +// TODO: (@soha) 대괄호 사용에 대해 논의 +export const COLORS: ColorTokens = { + white: PRIMITIVE_COLORS.white, + black: PRIMITIVE_COLORS.gray[700], + + primary: PRIMITIVE_COLORS.purple[300], + onPrimary: PRIMITIVE_COLORS.white, + secondary: PRIMITIVE_COLORS.purple[50], + onSecondary: PRIMITIVE_COLORS.purple[600], + tertiary: PRIMITIVE_COLORS.gray[200], + onTertiary: PRIMITIVE_COLORS.gray[700], + + gray: PRIMITIVE_COLORS.gray[400], + darkGray: PRIMITIVE_COLORS.gray[500], + grayContainer: PRIMITIVE_COLORS.gray[100], + lightGrayContainer: PRIMITIVE_COLORS.gray[50], + + error: PRIMITIVE_COLORS.pink[200], + errorContainer: PRIMITIVE_COLORS.pink[50], + onErrorContainer: PRIMITIVE_COLORS.pink[300], + warn: PRIMITIVE_COLORS.yellow[400], + complete: PRIMITIVE_COLORS.green[300], +}; diff --git a/HDesign/src/token/typography.ts b/HDesign/src/token/typography.ts new file mode 100644 index 000000000..c88d61ea9 --- /dev/null +++ b/HDesign/src/token/typography.ts @@ -0,0 +1,67 @@ +type Typography = Record; +export type TypographyTokens = Record; + +export const TYPOGRAPHY: TypographyTokens = { + head: { + fontFamily: 'Pretendard', + fontSize: '3rem', + lineHeight: '1.5', + fontWeight: '700', + }, + title: { + fontFamily: 'Pretendard', + fontSize: '2rem', + lineHeight: '1.5', + fontWeight: '700', + }, + subTitle: { + fontFamily: 'Pretendard', + fontSize: '1.5rem', + lineHeight: '1.5', + fontWeight: '700', + }, + bodyBold: { + fontFamily: 'Pretendard', + fontSize: '1rem', + lineHeight: '1.5', + fontWeight: '700', + }, + body: { + fontFamily: 'Pretendard', + fontSize: '1rem', + lineHeight: '1.5', + fontWeight: '400', + }, + smallBodyBold: { + fontFamily: 'Pretendard', + fontSize: '0.875rem', + lineHeight: '1.5', + fontWeight: '700', + }, + smallBody: { + fontFamily: 'Pretendard', + fontSize: '0.875rem', + lineHeight: '1.5', + fontWeight: '400', + }, + captionBold: { + fontFamily: 'Pretendard', + fontSize: '0.75rem', + lineHeight: '1.5', + fontWeight: '700', + }, + caption: { + fontFamily: 'Pretendard', + fontSize: '0.75rem', + lineHeight: '1.5', + fontWeight: '400', + }, + tiny: { + fontFamily: 'Pretendard', + fontSize: '0.625rem', + lineHeight: '1.5', + fontWeight: '400', + }, +}; + +export default TYPOGRAPHY; diff --git a/HDesign/src/type/strictPropsWithChildren.ts b/HDesign/src/type/strictPropsWithChildren.ts new file mode 100644 index 000000000..684fbcc76 --- /dev/null +++ b/HDesign/src/type/strictPropsWithChildren.ts @@ -0,0 +1,3 @@ +export type StrictPropsWithChildren

= P & { + children: React.ReactNode; +}; diff --git a/HDesign/src/type/withTheme.ts b/HDesign/src/type/withTheme.ts new file mode 100644 index 000000000..bae8dc318 --- /dev/null +++ b/HDesign/src/type/withTheme.ts @@ -0,0 +1,5 @@ +import {Theme} from '@theme/theme.type'; + +export type WithTheme

= P & { + theme: Theme; +}; diff --git a/HDesign/src/utils/changeCamelCaseToKebabCase.ts b/HDesign/src/utils/changeCamelCaseToKebabCase.ts new file mode 100644 index 000000000..2bca7c1b7 --- /dev/null +++ b/HDesign/src/utils/changeCamelCaseToKebabCase.ts @@ -0,0 +1,3 @@ +export const changeCamelCaseToKebabCase = (str: string) => { + return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); +}; diff --git a/HDesign/src/utils/colors.ts b/HDesign/src/utils/colors.ts new file mode 100644 index 000000000..116c670b0 --- /dev/null +++ b/HDesign/src/utils/colors.ts @@ -0,0 +1,88 @@ +export const hexToRgb = (hex: string) => { + hex = hex.slice(1); + if (hex.length === 3) { + hex = hex + .split('') + .reduce((acc, a) => { + acc.push(a + a); + return acc; + }, []) + .join(''); + } + + if (hex.length !== 6) { + throw new Error(`잘못된 색상값이 입력됐습니다. : ${hex} 3자리(#fff), 6자리(#fe0000)hex 값만 입력 가능합니다.`); + } + + const regex = new RegExp(`.{1,2}`, 'g'); + const hexArray = hex.match(regex) as string[]; + + return `rgb(${hexArray.map(n => parseInt(n, 16)).join(', ')})`; +}; + +export const rgbToColors = (rgb: string) => { + if (rgb.slice(0, 3) !== 'rgb') { + throw new Error('잘못된 색상값이 입력됐습니다. rgb() 값만 입력 가능합니다.'); + } + + return rgb + .slice(4, -1) + .split(',') + .map(a => Number(a.trim())); +}; + +export const hexToColors = (hex: string) => { + return rgbToColors(hexToRgb(hex)); +}; + +function intToHex(int: number) { + const hex = int.toString(16); + return hex.length === 1 ? `0${hex}` : hex; +} + +export const colorsToRgb = (colors: number[]) => { + return `rgb(${colors.join(', ')})`; +}; + +export const rgbToHex = (rgb: string) => { + const colors = rgbToColors(rgb); + return `#${colors.map((n, i) => intToHex(i === 3 ? Math.round(255 * n) : n)).join('')}`; +}; + +export const colorsToHex = (colors: number[]) => { + return rgbToHex(colorsToRgb(colors)); +}; + +export const setDarker = (hex: string, coefficient: number) => { + const colors = hexToColors(hex); + const adjustCoefficient = coefficient > 1 ? 1 : coefficient < 0 ? 0 : coefficient; + const darkerColors = colors.map(color => Math.round(color * (1 - adjustCoefficient))); + + return colorsToHex(darkerColors); +}; + +export const setLighter = (hex: string, coefficient: number) => { + const colors = hexToColors(hex); + const adjustCoefficient = coefficient > 1 ? 1 : coefficient < 0 ? 0 : coefficient; + const lighterColors = colors.map(color => Math.round(color + (255 - color) * adjustCoefficient)); + + return colorsToHex(lighterColors); +}; + +export const getLuminance = (hex: string) => { + const colors = hexToColors(hex); + const values = colors.map(color => { + const value = color / 255; + return value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4; + }); + + return Number((0.2126 * values[0] + 0.7152 * values[1] + 0.0722 * values[2]).toFixed(3)); +}; + +export const setEmphasize = (hex: string, threshold: number, coefficient = 0.15) => { + return getLuminance(hex) > threshold ? setDarker(hex, coefficient) : setLighter(hex, coefficient); +}; + +export const setOnTextColor = (hex: string, threshold: number, blackHex: string, whiteHex: string) => { + return getLuminance(hex) > threshold ? blackHex : whiteHex; +}; diff --git a/HDesign/tsconfig.json b/HDesign/tsconfig.json new file mode 100644 index 000000000..ca7b8b78f --- /dev/null +++ b/HDesign/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "sourceMap": true, + "outDir": "./dist", + "target": "ES5", + "skipLibCheck": true, + "module": "commonjs", + "moduleResolution": "node", + "strict": true, + "declaration": true, + "declarationDir": "./dist", + "resolveJsonModule": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "jsx": "react-jsx", + "allowJs": true, + "baseUrl": ".", + "paths": { + "@*": ["src/*"], + "@components/*": ["src/components/*"], + "@layouts/*": ["src/layouts/*"], + "@token/*": ["src/token/*"], + "@type/*": ["src/type/*"], + "@theme/*": ["src/theme/*"], + "@assets/*": ["src/assets/*"], + "@utils/*": ["src/utils/*"] + }, + "jsxImportSource": "@emotion/react", + "allowSyntheticDefaultImports": true + }, + "include": ["src"], + "exclude": ["./node_modules", "dist"] +} diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 000000000..cf03bec6b --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,14 @@ +logs +*.log +npm-debug.log* + +node_modules +dist + +.env.* + +*storybook.log +.DS_Store + +# Sentry Config File +.env.sentry-build-plugin diff --git a/client/.gitkeep b/client/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/.npmrc b/client/.npmrc new file mode 100644 index 000000000..ece05f588 --- /dev/null +++ b/client/.npmrc @@ -0,0 +1,2 @@ +engine-strict = true +legacy-peer-deps = true diff --git a/client/.prettierrc b/client/.prettierrc new file mode 100644 index 000000000..94ad823ef --- /dev/null +++ b/client/.prettierrc @@ -0,0 +1,12 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120, + "tabWidth": 2, + "semi": true, + "arrowParens": "avoid", + "endOfLine": "auto", + "jsxSingleQuote": false, + "bracketSpacing": false, + "proseWrap": "preserve" +} \ No newline at end of file diff --git a/client/cypress.config.ts b/client/cypress.config.ts new file mode 100644 index 000000000..2261e7871 --- /dev/null +++ b/client/cypress.config.ts @@ -0,0 +1,12 @@ +import {defineConfig} from 'cypress'; + +export default defineConfig({ + e2e: { + baseUrl: 'http://localhost:3000', + viewportWidth: 430, + viewportHeight: 930, + // setupNodeEvents(on, config) { + // // implement node event listeners here + // }, + }, +}); diff --git a/client/cypress/constants/constants.ts b/client/cypress/constants/constants.ts new file mode 100644 index 000000000..393ef5361 --- /dev/null +++ b/client/cypress/constants/constants.ts @@ -0,0 +1,6 @@ +const CONSTANTS = { + eventName: '테스트 이벤트', + eventPassword: '1234', +}; + +export default CONSTANTS; diff --git a/client/cypress/e2e/createEvent.cy.ts b/client/cypress/e2e/createEvent.cy.ts new file mode 100644 index 000000000..5b4a93884 --- /dev/null +++ b/client/cypress/e2e/createEvent.cy.ts @@ -0,0 +1,79 @@ +import CONSTANTS from '../constants/constants'; +beforeEach(() => { + cy.blockSentry(); +}); + +describe('Flow: 랜딩 페이지에서부터 이벤트를 생성 완료하는 flow', () => { + it('랜딩페이지에서 "행사 생성하기" 버튼을 눌러 행사 이름 입력 페이지로 이동해야 한다.', () => { + cy.visit('/'); + cy.get('header').find('button').click(); + cy.url().should('include', '/event/create/name'); + }); + + context('행사 이름 입력 페이지', () => { + beforeEach(() => { + cy.visit('/event/create/name'); + }); + + it('행사 이름 입력 페이지에서 input이 포커싱 되어 있고, "다음" 버튼이 비활성화 되어 있어야 한다.', () => { + cy.get('input').focused(); + cy.get('button').contains('다음').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/name'); + }); + + it('행사 이름이 1자 이상 입력된 경우 "다음" 버튼이 활성화 되고, 값이 없는 경우 "다음" 버튼이 비활성화 되어야 한다.', () => { + cy.get('input').type(CONSTANTS.eventName); + cy.get('button').contains('다음').should('not.have.attr', 'disabled'); + cy.get('input').clear(); + cy.get('input').should('have.value', ''); + cy.get('button').contains('다음').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/name'); + }); + + it('행사 이름을 입력한 후 "다음" 버튼을 누르면 행사 비밀번호 설정 화면으로 이동해야 한다.', () => { + cy.get('input').type(CONSTANTS.eventName); + cy.get('button').contains('다음').click(); + cy.url().should('include', '/event/create/password'); + }); + }); + + context('행사 비밀번호 입력 페이지', () => { + beforeEach(() => { + cy.createEventName(CONSTANTS.eventName); + }); + + it('행사 비밀번호 입력 페이지에서 input이 포커싱 되어 있고, "행동 개시!" 버튼이 비활성화 되어 있어야 한다.', () => { + cy.get('input').focused(); + cy.get('button').contains('행동 개시!').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/password'); + }); + + it('행사 비밀번호에 숫자가 아닌 입력을 할 경우 값이 입력되지 않아야 한다.', () => { + cy.get('input').type('테스트'); + cy.get('input').should('have.value', ''); + }); + + it('행사 비밀번호에 4자리 이상 입력을 할 경우 처음 네 자리만 입력되어야 한다.', () => { + cy.get('input').type('12345'); + cy.get('input').should('have.value', CONSTANTS.eventPassword); + }); + + it('행사 비밀번호이 1자 이상 입력된 경우 "행동 개시!" 버튼이 활성화 되고, 값이 없는 경우 "행동 개시!" 버튼이 비활성화 되어야 한다.', () => { + cy.get('input').type(CONSTANTS.eventPassword); + cy.get('button').contains('행동 개시!').should('not.have.attr', 'disabled'); + cy.get('input').clear(); + cy.get('input').should('have.value', ''); + cy.get('button').contains('행동 개시!').should('have.attr', 'disabled'); + cy.url().should('include', '/event/create/password'); + }); + + it('행사 비밀번호을 입력한 후 "행동 개시!" 버튼을 누르면 행사 생성 완료 화면으로 이동해야 한다.', () => { + cy.interceptAPI({type: 'postEvent', statusCode: 200}); + cy.interceptAPI({type: 'getEventName', statusCode: 200}); + cy.get('input').type(CONSTANTS.eventPassword); + cy.get('button').contains('행동 개시!').click(); + + cy.url().should('include', '/event/create/complete'); + }); + }); +}); diff --git a/client/cypress/fixtures/postEvent.json b/client/cypress/fixtures/postEvent.json new file mode 100644 index 000000000..63b91e17b --- /dev/null +++ b/client/cypress/fixtures/postEvent.json @@ -0,0 +1,3 @@ +{ + "eventId": "550e8400-e29b-41d4-a716-446655440000" +} \ No newline at end of file diff --git a/client/cypress/support/commands.ts b/client/cypress/support/commands.ts new file mode 100644 index 000000000..c51d00580 --- /dev/null +++ b/client/cypress/support/commands.ts @@ -0,0 +1,58 @@ +import CONSTANTS from '../constants/constants'; + +type APIType = 'sentry' | 'postEvent' | 'getEventName'; + +interface InterceptAPIProps { + type: APIType; + delay?: number; + statusCode?: number; +} +const POST_EVENT = { + method: 'POST', + url: /.*api\/events.*/, +}; + +const GET_EVENT_NAME = { + method: 'GET', + url: /.*api\/events\.*/, +}; + +Cypress.Commands.add('blockSentry', () => { + cy.intercept('POST', /.*sentry.io\/api.*/, {statusCode: 200}).as('sentry'); +}); + +Cypress.Commands.add('interceptAPI', ({type, delay = 0, statusCode = 200}: InterceptAPIProps) => { + if (type === 'postEvent') + cy.intercept(POST_EVENT, { + delay, + statusCode, + fixture: 'postEvent.json', + }).as('postEvent'); + if (type === 'getEventName') + cy.intercept(GET_EVENT_NAME, { + delay, + statusCode, + body: { + eventName: CONSTANTS.eventName, + }, + }).as('getEventName'); +}); + +Cypress.Commands.add('createEventName', (eventName: string) => { + cy.visit('/event/create/name'); + cy.get('input').type(eventName); + cy.get('button').contains('다음').click(); + cy.url().should('include', '/event/create/password'); +}); + +declare global { + namespace Cypress { + interface Chainable { + blockSentry(): Chainable; + interceptAPI(props: InterceptAPIProps): Chainable; + createEventName(eventName: string): Chainable; + } + } +} + +export {}; diff --git a/client/cypress/support/e2e.ts b/client/cypress/support/e2e.ts new file mode 100644 index 000000000..1221b17e0 --- /dev/null +++ b/client/cypress/support/e2e.ts @@ -0,0 +1 @@ +import './commands'; diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs new file mode 100644 index 000000000..4ca5abb89 --- /dev/null +++ b/client/eslint.config.mjs @@ -0,0 +1,112 @@ +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; +import reactPlugin from 'eslint-plugin-react'; +import tsPlugin from '@typescript-eslint/eslint-plugin'; +import importPlugin from 'eslint-plugin-import'; +import prettierPlugin from 'eslint-plugin-prettier'; +import typescriptParser from '@typescript-eslint/parser'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +export default [ + { + files: ['src/**/*.{js,jsx,ts,tsx}'], + languageOptions: { + ecmaVersion: 2021, + sourceType: 'module', + parser: typescriptParser, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + plugins: { + react: reactPlugin, + '@typescript-eslint': tsPlugin, + import: importPlugin, + prettier: prettierPlugin, + }, + rules: { + 'prettier/prettier': 'error', + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + 'react/jsx-uses-vars': 'error', + // '@typescript-eslint/no-use-before-define': ['error'], + // '@typescript-eslint/explicit-module-boundary-types': 'error', + // "import/no-unresolved": "error", + 'import/order': [ + 'error', + { + 'newlines-between': 'always', + groups: ['type', 'builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], + pathGroups: [ + { + pattern: 'react*', + group: 'external', + position: 'before', + }, + { + pattern: '@hooks/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@apis/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@store/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@pages/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@components/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@utils/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@assets/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@constants/*', + group: 'internal', + position: 'after', + }, + { + pattern: '@mocks/*', + group: 'internal', + position: 'after', + }, + ], + }, + ], + }, + settings: { + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + typescript: { + directory: './src', + }, + }, + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + }, + }, +]; diff --git a/client/favicon.ico b/client/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2be6241f8e7c02630efcc4cf714d8f9813cf7524 GIT binary patch literal 44932 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 + + + + + + + + + + + + + + + + + + + 행동대장 + + +

+ + diff --git a/client/jest.config.ts b/client/jest.config.ts new file mode 100644 index 000000000..a75677a5a --- /dev/null +++ b/client/jest.config.ts @@ -0,0 +1,49 @@ +import type {Config} from 'jest'; + +const config: Config = { + preset: 'ts-jest', + // testEnvironment: 'node', // Node.js 모듈(fs, path, http 등)을 사용한 서버 사이드 로직이나 파일 시스템 접근, 네트워크 요청 등을 테스트 + testEnvironment: 'jsdom', // 브라우저 내에서의 JavaScript 동작을 모방하여, DOM 조작, 이벤트 핸들링, 브라우저 관련 API 호출 + transform: { + '^.+\\.ts?$': 'ts-jest', + }, + collectCoverage: true, + coverageReporters: ['text'], + coveragePathIgnorePatterns: [ + '/node_modules/', + '/src/utils/', + '/src/mocks/', + '/src/apis/', + '/src/request/', + '/src/constants/', + '/src/errors/', + '/src/components/', + '/src/store/', + '/src/pages/', + '/src/hooks/queries', + ], + + verbose: true, + setupFiles: ['./jest.polyfills.ts'], + setupFilesAfterEnv: ['./jest.setup.ts'], + transformIgnorePatterns: ['/node_modules/'], + moduleNameMapper: { + '@/(.*)$': '/src/$1', // path alias를 적용하기 위함 + '^@apis/(.*)$': '/src/apis/$1', + '^@constants/(.*)$': '/src/constants/$1', + '^@components/(.*)$': '/src/components/$1', + '^@hooks/(.*)$': '/src/hooks/$1', + '^@utils/(.*)$': '/src/utils/$1', + '^@pages/(.*)$': '/src/pages/$1', + '^@types/(.*)$': '/src/types/$1', + '^@errors/(.*)$': '/src/errors/$1', + '^@mocks/(.*)$': '/src/mocks/$1', + '^@store/(.*)$': '/src/store/$1', + '\\.svg$': '/src/mocks/svg.ts', + }, + testEnvironmentOptions: { + customExportConditions: [''], + }, +}; + +export default config; diff --git a/client/jest.polyfills.ts b/client/jest.polyfills.ts new file mode 100644 index 000000000..16547bc80 --- /dev/null +++ b/client/jest.polyfills.ts @@ -0,0 +1,20 @@ +import {TextDecoder, TextEncoder} from 'node:util'; + +Object.defineProperties(globalThis, { + TextDecoder: {value: TextDecoder}, + TextEncoder: {value: TextEncoder}, +}); + +import {Blob, File} from 'node:buffer'; + +import {fetch, Headers, FormData, Request, Response} from 'undici'; + +Object.defineProperties(globalThis, { + fetch: {value: fetch, writable: true}, + Blob: {value: Blob}, + File: {value: File}, + Headers: {value: Headers}, + FormData: {value: FormData}, + Request: {value: Request}, + Response: {value: Response}, +}); diff --git a/client/jest.setup.ts b/client/jest.setup.ts new file mode 100644 index 000000000..33c8f6a70 --- /dev/null +++ b/client/jest.setup.ts @@ -0,0 +1,24 @@ +import {server} from './src/mocks/server'; +import * as router from 'react-router'; +import '@testing-library/jest-dom'; // toBeInTheDocument를 인식하기 위해 @testing-library/jest-dom/extend-expect추가 +import 'jest-canvas-mock'; // jsdom은 canvas를 추가할 수 없기 때문에 이를 해결하는 라이브러리 추가 + +beforeAll(() => { + server.listen(); + + Object.defineProperty(window, 'location', { + writable: true, + value: { + ...window.location, + pathname: '/event/abc-123/', // 원하는 pathname 설정 + }, + }); +}); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +beforeAll(() => {}); +jest.mock('./src/utils/captureError'); +jest.mock('./src/utils/sendLogToSentry'); + +jest.spyOn(router, 'useNavigate').mockImplementation(() => jest.fn()); diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 000000000..61a529538 --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,19037 @@ +{ + "name": "haengdong-client", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "haengdong-client", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@emotion/react": "^11.11.4", + "@sentry/react": "^8.25.0", + "@tanstack/react-query": "^5.51.23", + "haengdong-design": "^0.1.81", + "jest-canvas-mock": "^2.5.2", + "react": "^18.3.1", + "react-copy-to-clipboard": "^5.1.0", + "react-dom": "^18.3.1", + "react-error-boundary": "^4.0.13", + "react-router-dom": "^6.24.1", + "zustand": "^4.5.5" + }, + "devDependencies": { + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@jest/types": "^29.6.3", + "@sentry/webpack-plugin": "^2.22.0", + "@svgr/webpack": "^8.1.0", + "@tanstack/react-query-devtools": "^5.52.0", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.4.8", + "@testing-library/react": "^16.0.0", + "@types/dotenv-webpack": "^7.0.7", + "@types/jest": "^29.5.12", + "@types/react": "^18.3.3", + "@types/react-copy-to-clipboard": "^5.0.7", + "@types/react-dom": "^18.3.0", + "@types/testing-library__jest-dom": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "cypress": "^13.13.2", + "dotenv-webpack": "^8.1.0", + "eslint": "^9.6.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.3", + "eslint-plugin-react-hooks": "^4.6.2", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jsdom": "^24.1.1", + "modify-source-webpack-plugin": "^4.1.0", + "msw": "^2.3.5", + "prettier": "3.3.2", + "ts-jest": "^29.2.4", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "typescript": "^5.5.4", + "typescript-eslint": "^7.16.0", + "undici": "^5.28.4", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4", + "webpack-merge": "^6.0.1" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@babel/generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "dependencies": { + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", + "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", + "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", + "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dependencies": { + "@babel/types": "^7.25.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", + "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", + "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", + "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz", + "integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", + "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", + "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", + "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", + "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", + "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", + "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", + "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", + "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-simple-access": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", + "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "dependencies": { + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", + "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", + "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", + "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", + "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", + "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", + "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", + "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", + "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.1.tgz", + "integrity": "sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz", + "integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz", + "integrity": "sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz", + "integrity": "sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", + "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", + "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", + "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz", + "integrity": "sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", + "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", + "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", + "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", + "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.0", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.7.tgz", + "integrity": "sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.24.7", + "@babel/plugin-transform-react-jsx-development": "^7.24.7", + "@babel/plugin-transform-react-pure-annotations": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", + "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", + "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", + "dev": true, + "dependencies": { + "cookie": "^0.5.0" + } + }, + "node_modules/@bundled-es-modules/cookie/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "dev": true, + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "dev": true, + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@cypress/request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.10.4", + "safe-buffer": "^5.1.2", + "tough-cookie": "^4.1.3", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/request/node_modules/qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", + "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", + "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.9.0", + "@emotion/utils": "^1.4.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/unitless": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.1.1.tgz", + "integrity": "sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@inquirer/confirm": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", + "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", + "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "dev": true, + "dependencies": { + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.2", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.1.0", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "cli-spinners": "^2.9.2", + "cli-width": "^4.1.0", + "mute-stream": "^1.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@inquirer/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", + "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", + "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", + "dev": true, + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", + "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@mswjs/interceptors": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.29.1.tgz", + "integrity": "sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==", + "dev": true, + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "dev": true + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@remix-run/router": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz", + "integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@sentry-internal/browser-utils": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.25.0.tgz", + "integrity": "sha512-nlWgp1lVhNQOTUplW85G3qm0fOIgAhJ/sl/31OIuScVrITYhYDF2bO+Zv/jQ8YsdUBAUXqY1tPT9wwPJklnPhw==", + "dependencies": { + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry-internal/feedback": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.25.0.tgz", + "integrity": "sha512-327I5XJAFrsgjc5qUKxZ9rff3WNCfGvf1fIii70LQ2YQhQgG4XHZILmkD06ETEyXb+H1tkrNQQEJ1/d4ai+q5g==", + "dependencies": { + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry-internal/replay": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.25.0.tgz", + "integrity": "sha512-3f7x8EYthyj157uV9V8vBjun+1gJnHhh2+i0qxYLhMGx7N2Fq0J3Bvvo1rosSg+fYh5HzPNZDufwIRdg5C/MQw==", + "dependencies": { + "@sentry-internal/browser-utils": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry-internal/replay-canvas": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.25.0.tgz", + "integrity": "sha512-dPXlkAbkFL1DBum8rGTaHS+apJKaXEZJF9gLcBBKTruhTCizrugFLxajzIfVSiFVuwNKuJWa2fzhzbeQM0ee7w==", + "dependencies": { + "@sentry-internal/replay": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/babel-plugin-component-annotate": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.0.tgz", + "integrity": "sha512-UzH+NNhgnOo6UFku3C4TEz+pO/yDcIA5FKTJvLbJ7lQwAjsqLs3DZWm4cCA08skICb8mULArF6S/dn5/butVCA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@sentry/browser": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.25.0.tgz", + "integrity": "sha512-51bdVGXjyooqVGzaSGsnExqRTt9NvZ1zGFsxbbCSXi5UoEFN6zdMUz6jKYsL2K80eeELP2VKOVlobHlEzeJQfw==", + "dependencies": { + "@sentry-internal/browser-utils": "8.25.0", + "@sentry-internal/feedback": "8.25.0", + "@sentry-internal/replay": "8.25.0", + "@sentry-internal/replay-canvas": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/bundler-plugin-core": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.0.tgz", + "integrity": "sha512-/xXN8o7565WMsewBnQFfjm0E5wqhYsegg++HJ5RjrY/cTM4qcd/ven44GEMxqGFJitZizvkk3NHszaHylzcRUw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.18.5", + "@sentry/babel-plugin-component-annotate": "2.22.0", + "@sentry/cli": "^2.33.1", + "dotenv": "^16.3.1", + "find-up": "^5.0.0", + "glob": "^9.3.2", + "magic-string": "0.30.8", + "unplugin": "1.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@sentry/bundler-plugin-core/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@sentry/bundler-plugin-core/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@sentry/bundler-plugin-core/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/cli": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.33.1.tgz", + "integrity": "sha512-dUlZ4EFh98VFRPJ+f6OW3JEYQ7VvqGNMa0AMcmvk07ePNeK/GicAWmSQE4ZfJTTl80ul6HZw1kY01fGQOQlVRA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.7", + "progress": "^2.0.3", + "proxy-from-env": "^1.1.0", + "which": "^2.0.2" + }, + "bin": { + "sentry-cli": "bin/sentry-cli" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@sentry/cli-darwin": "2.33.1", + "@sentry/cli-linux-arm": "2.33.1", + "@sentry/cli-linux-arm64": "2.33.1", + "@sentry/cli-linux-i686": "2.33.1", + "@sentry/cli-linux-x64": "2.33.1", + "@sentry/cli-win32-i686": "2.33.1", + "@sentry/cli-win32-x64": "2.33.1" + } + }, + "node_modules/@sentry/cli-darwin": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.33.1.tgz", + "integrity": "sha512-+4/VIx/E1L2hChj5nGf5MHyEPHUNHJ/HoG5RY+B+vyEutGily1c1+DM2bum7RbD0xs6wKLIyup5F02guzSzG8A==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-arm": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.33.1.tgz", + "integrity": "sha512-zbxEvQju+tgNvzTOt635le4kS/Fbm2XC2RtYbCTs034Vb8xjrAxLnK0z1bQnStUV8BkeBHtsNVrG+NSQDym2wg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux", + "freebsd" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-arm64": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.33.1.tgz", + "integrity": "sha512-DbGV56PRKOLsAZJX27Jt2uZ11QfQEMmWB4cIvxkKcFVE+LJP4MVA+MGGRUL6p+Bs1R9ZUuGbpKGtj0JiG6CoXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux", + "freebsd" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-i686": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.33.1.tgz", + "integrity": "sha512-g2LS4oPXkPWOfKWukKzYp4FnXVRRSwBxhuQ9eSw2peeb58ZIObr4YKGOA/8HJRGkooBJIKGaAR2mH2Pk1TKaiA==", + "cpu": [ + "x86", + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux", + "freebsd" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-x64": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.33.1.tgz", + "integrity": "sha512-IV3dcYV/ZcvO+VGu9U6kuxSdbsV2kzxaBwWUQxtzxJ+cOa7J8Hn1t0koKGtU53JVZNBa06qJWIcqgl4/pCuKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux", + "freebsd" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-i686": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.33.1.tgz", + "integrity": "sha512-F7cJySvkpzIu7fnLKNHYwBzZYYwlhoDbAUnaFX0UZCN+5DNp/5LwTp37a5TWOsmCaHMZT4i9IO4SIsnNw16/zQ==", + "cpu": [ + "x86", + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-x64": { + "version": "2.33.1", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.33.1.tgz", + "integrity": "sha512-8VyRoJqtb2uQ8/bFRKNuACYZt7r+Xx0k2wXRGTyH05lCjAiVIXn7DiS2BxHFty7M1QEWUCMNsb/UC/x/Cu2wuA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/core": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.25.0.tgz", + "integrity": "sha512-7KtglbrW1eX4DOHkf6i4rRIExEf2CgtQ99qZ8gn5FUaAmNMg0rK7bb1yZMx0RZtp5G1TSz/S0jQQgxHWebaEig==", + "dependencies": { + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/react": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-8.25.0.tgz", + "integrity": "sha512-A3QeSCJEa+lpo5nh0kxKeqsmnuW2nycKNN/0bpXPv5T5jiEfExSmEBVM0zutrQpf+J0WRIl1AGunUYGPO+GPQg==", + "dependencies": { + "@sentry/browser": "8.25.0", + "@sentry/core": "8.25.0", + "@sentry/types": "8.25.0", + "@sentry/utils": "8.25.0", + "hoist-non-react-statics": "^3.3.2" + }, + "engines": { + "node": ">=14.18" + }, + "peerDependencies": { + "react": "^16.14.0 || 17.x || 18.x || 19.x" + } + }, + "node_modules/@sentry/types": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-8.25.0.tgz", + "integrity": "sha512-ojim0gDcRhGJPguYrtms4FsprX4xZz3LGNk9Z0hwTbSVEdlhQIInsQ7CYcdM3sjUs+qT7kfpxTRZGUeZNRRJcA==", + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/utils": { + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-8.25.0.tgz", + "integrity": "sha512-mVlkV7S62ZZ2jM38/kOwWx2xoW8fUv2cjw2IwFKoAIPyLBh3mo1WJtvfdtN/rXGjQWZJBKW53EWaWnD00rkjyA==", + "dependencies": { + "@sentry/types": "8.25.0" + }, + "engines": { + "node": ">=14.18" + } + }, + "node_modules/@sentry/webpack-plugin": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-2.22.0.tgz", + "integrity": "sha512-u2brctki0AMCoZksdAConQSYE6PokRVeZ4YYsbnJYkAi0KuaQnczsRwS9e2L0bK2CmZ7QdyYcrjaXHNlXaFDbQ==", + "dev": true, + "dependencies": { + "@sentry/bundler-plugin-core": "2.22.0", + "unplugin": "1.0.1", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "webpack": ">=4.40.0" + } + }, + "node_modules/@sentry/webpack-plugin/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@storybook/addon-webpack5-compiler-swc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@storybook/addon-webpack5-compiler-swc/-/addon-webpack5-compiler-swc-1.0.5.tgz", + "integrity": "sha512-1NlM3noit2vA22OyWb8Ma2lhcEKCS1Snv2kr+EkaVABUqNDfVc9AD/GgYQhF7F/2CoF5N2JU7uzXDzFHd5TzZg==", + "dependencies": { + "@swc/core": "^1.7.3", + "swc-loader": "^0.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@swc/core": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.14.tgz", + "integrity": "sha512-9aeXeifnyuvc2pcuuhPQgVUwdpGEzZ+9nJu0W8/hNl/aESFsJGR5i9uQJRGu0atoNr01gK092fvmqMmQAPcKow==", + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.12" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.7.14", + "@swc/core-darwin-x64": "1.7.14", + "@swc/core-linux-arm-gnueabihf": "1.7.14", + "@swc/core-linux-arm64-gnu": "1.7.14", + "@swc/core-linux-arm64-musl": "1.7.14", + "@swc/core-linux-x64-gnu": "1.7.14", + "@swc/core-linux-x64-musl": "1.7.14", + "@swc/core-win32-arm64-msvc": "1.7.14", + "@swc/core-win32-ia32-msvc": "1.7.14", + "@swc/core-win32-x64-msvc": "1.7.14" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.14.tgz", + "integrity": "sha512-V0OUXjOH+hdGxDYG8NkQzy25mKOpcNKFpqtZEzLe5V/CpLJPnpg1+pMz70m14s9ZFda9OxsjlvPbg1FLUwhgIQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.14.tgz", + "integrity": "sha512-9iFvUnxG6FC3An5ogp5jbBfQuUmTTwy8KMB+ZddUoPB3NR1eV+Y9vOh/tfWcenSJbgOKDLgYC5D/b1mHAprsrQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.14.tgz", + "integrity": "sha512-zGJsef9qPivKSH8Vv4F/HiBXBTHZ5Hs3ZjVGo/UIdWPJF8fTL9OVADiRrl34Q7zOZEtGXRwEKLUW1SCQcbDvZA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.14.tgz", + "integrity": "sha512-AxV3MPsoI7i4B8FXOew3dx3N8y00YoJYvIPfxelw07RegeCEH3aHp2U2DtgbP/NV1ugZMx0TL2Z2DEvocmA51g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.14.tgz", + "integrity": "sha512-JDLdNjUj3zPehd4+DrQD8Ltb3B5lD8D05IwePyDWw+uR/YPc7w/TX1FUVci5h3giJnlMCJRvi1IQYV7K1n7KtQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.14.tgz", + "integrity": "sha512-Siy5OvPCLLWmMdx4msnEs8HvEVUEigSn0+3pbLjv78iwzXd0qSBNHUPZyC1xeurVaUbpNDxZTpPRIwpqNE2+Og==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.14.tgz", + "integrity": "sha512-FtEGm9mwtRYQNK43WMtUIadxHs/ja2rnDurB99os0ZoFTGG2IHuht2zD97W0wB8JbqEabT1XwSG9Y5wmN+ciEQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.14.tgz", + "integrity": "sha512-Jp8KDlfq7Ntt2/BXr0y344cYgB1zf0DaLzDZ1ZJR6rYlAzWYSccLYcxHa97VGnsYhhPspMpmCvHid97oe2hl4A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.14.tgz", + "integrity": "sha512-I+cFsXF0OU0J9J4zdWiQKKLURO5dvCujH9Jr8N0cErdy54l9d4gfIxdctfTF+7FyXtWKLTCkp+oby9BQhkFGWA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.7.14", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.14.tgz", + "integrity": "sha512-NNrprQCK6d28mG436jVo2TD+vACHseUECacEBGZ9Ef0qfOIWS1XIt2MisQKG0Oea2VvLFl6tF/V4Lnx/H0Sn3Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, + "node_modules/@swc/types": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", + "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.51.21", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.21.tgz", + "integrity": "sha512-POQxm42IUp6n89kKWF4IZi18v3fxQWFRolvBA6phNVmA8psdfB1MvDnGacCJdS+EOX12w/CyHM62z//rHmYmvw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.51.16", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.51.16.tgz", + "integrity": "sha512-ajwuq4WnkNCMj/Hy3KR8d3RtZ6PSKc1dD2vs2T408MdjgKzQ3klVoL6zDgVO7X+5jlb5zfgcO3thh4ojPhfIaw==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.51.23", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.51.23.tgz", + "integrity": "sha512-CfJCfX45nnVIZjQBRYYtvVMIsGgWLKLYC4xcUiYEey671n1alvTZoCBaU9B85O8mF/tx9LPyrI04A6Bs2THv4A==", + "dependencies": { + "@tanstack/query-core": "5.51.21" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.52.0.tgz", + "integrity": "sha512-oq8bDxMQ95edOlcWFaGsnSFzH11s06M1uiNiLtgsm+UG6Y5w+K6BJp0GeXN8q7sBNVBw/WPyeFdUH8rj9RT2Aw==", + "dev": true, + "dependencies": { + "@tanstack/query-devtools": "5.51.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.52.0", + "react": "^18 || ^19" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/@testing-library/dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.8.tgz", + "integrity": "sha512-JD0G+Zc38f5MBHA4NgxQMR5XtO5Jx9g86jqturNTt2WUfRmLDIY7iKkWHDCCTiDuFMre6nxAD5wHw9W5kI4rGw==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true + }, + "node_modules/@testing-library/jest-dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.0.tgz", + "integrity": "sha512-guuxUKRWQ+FgNX0h0NS0FIq3Q3uLtWVpBzcLOggmfMoUpgBnzBzvLLd4fbm6yS8ydJd94cIfY4yP9qUQjM2KwQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true + }, + "node_modules/@types/dotenv-webpack": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/dotenv-webpack/-/dotenv-webpack-7.0.7.tgz", + "integrity": "sha512-tltVokFUeYuSjNmHc6N892Asu/JIQcnH2iUF5A29/VKqv9opq6KlrmnKd/Lt/bBikV/z0YN2K0kguTwWirYCMQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.14", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", + "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", + "dev": true, + "dependencies": { + "undici-types": "~6.13.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", + "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-copy-to-clipboard": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.7.tgz", + "integrity": "sha512-Gft19D+as4M+9Whq1oglhmK49vqPhcLzk8WfvfLvaYMIPYanyfLy0+CwFucMJfdKoSFyySPmkkWn8/E6voQXjQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", + "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "dev": true + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/statuses": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", + "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", + "dev": true + }, + "node_modules/@types/testing-library__jest-dom": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-6.0.0.tgz", + "integrity": "sha512-bnreXCgus6IIadyHNlN/oI5FfX4dWgvGhOPvpr7zzCYDGAPIfvyIoAozMBINmhmsVuqV0cncejF2y5KC7ScqOg==", + "deprecated": "This is a stub types definition. @testing-library/jest-dom provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "@testing-library/jest-dom": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true + }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", + "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==", + "dev": true + }, + "node_modules/axe-core": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", + "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", + "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", + "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001649", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001649.tgz", + "integrity": "sha512-fJegqZZ0ZX8HOWr6rcafGr72+xcgJKI9oWfDW5DrD7ExUtgZC7a7R7ZYmZqplh7XDocFdGeIFn7roAxhOeYrPQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-js-compat": { + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.0.tgz", + "integrity": "sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==", + "dependencies": { + "browserslist": "^4.23.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/create-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/create-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/create-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssfontparser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", + "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==" + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/cypress": { + "version": "13.13.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.2.tgz", + "integrity": "sha512-PvJQU33933NvS1StfzEb8/mu2kMy4dABwCF+yd5Bi7Qly1HOVf+Bufrygee/tlmty/6j5lX+KIi8j9Q3JUMbhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@cypress/request": "^3.0.1", + "@cypress/xvfb": "^1.2.4", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.7.1", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.1", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "process": "^0.11.10", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.5.3", + "supports-color": "^8.1.1", + "tmp": "~0.2.3", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + } + }, + "node_modules/cypress/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cypress/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cypress/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cypress/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/cypress/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cypress/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cypress/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/cypress/node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true + }, + "node_modules/cypress/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cypress/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", + "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dev": true, + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-defaults/node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", + "integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==", + "dev": true, + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", + "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", + "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.8.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "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.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", + "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.9.1", + "axobject-query": "~3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.35.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", + "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.19", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "dev": true, + "dependencies": { + "async": "^3.2.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphql": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/haengdong-design": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/haengdong-design/-/haengdong-design-0.1.81.tgz", + "integrity": "sha512-IiXkt0zXSEmn7vstTLOeNZLFS35JO8lXbXavM55wdyAJd+w0e5kfRxyDk/K2oSiAnX2c2YPiGep/A0x2/gZPDg==", + "dependencies": { + "@emotion/react": "^11.11.4", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@svgr/webpack": "^8.1.0", + "lottie-react": "^2.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.24.1" + }, + "engines": { + "node": ">=20.15.1", + "npm": ">=10.7.0" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/headers-polyfill": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", + "dev": true + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-loader": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.1.0.tgz", + "integrity": "sha512-Jb3xwDbsm0W3qlXrCZwcYqYGnYz55hb6aoKQTlzyZPXsPpi6tHXzAfqalecglMQgNvtEfxrCQPaKT90Irt5XDA==", + "dev": true, + "dependencies": { + "html-minifier-terser": "^7.2.0", + "parse5": "^7.1.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-canvas-mock": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jest-canvas-mock/-/jest-canvas-mock-2.5.2.tgz", + "integrity": "sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==", + "dependencies": { + "cssfontparser": "^1.2.1", + "moo-color": "^1.0.2" + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-jsdom/node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom/node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/jest-environment-jsdom/node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-environment-jsdom/node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-environment-jsdom/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-environment-jsdom/node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-jsdom/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jest-environment-jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-jsdom/node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-haste-map/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/jsdom": { + "version": "24.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz", + "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==", + "dev": true, + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launch-editor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", + "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/listr2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/listr2/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils-webpack-v4": { + "name": "loader-utils", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lottie-react": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.0.tgz", + "integrity": "sha512-pDJGj+AQlnlyHvOHFK7vLdsDcvbuqvwPZdMlJ360wrzGFurXeKPr8SiRCjLf3LrNYKANQtSsh5dz9UYQHuqx4w==", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/modify-source-webpack-plugin": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/modify-source-webpack-plugin/-/modify-source-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-UaLQyFXoPWpWxkNUBFo9BotC20CCAGe7HEX9iKtB0P0MgNXgURf9TXUgNGuY5iVV5lDDQtcMjT2vneQWnNmwEw==", + "dev": true, + "dependencies": { + "loader-utils-webpack-v4": "npm:loader-utils@^2.0.4", + "schema-utils": "^4.0.0" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + } + }, + "node_modules/modify-source-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/modify-source-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/modify-source-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/modify-source-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/moo-color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz", + "integrity": "sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==", + "dependencies": { + "color-name": "^1.1.4" + } + }, + "node_modules/moo-color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/msw": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.3.5.tgz", + "integrity": "sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.0", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^3.0.0", + "@mswjs/interceptors": "^0.29.0", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "chalk": "^4.1.2", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.2", + "path-to-regexp": "^6.2.0", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.9.0", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.7.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/msw/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/msw/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/msw/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/msw/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/msw/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/msw/node_modules/path-to-regexp": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "dev": true + }, + "node_modules/msw/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", + "dev": true + }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "dev": true + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "dependencies": { + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^15.3.0 || 16 || 17 || 18" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-error-boundary": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.13.tgz", + "integrity": "sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-router": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz", + "integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==", + "dependencies": { + "@remix-run/router": "1.19.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.0.tgz", + "integrity": "sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==", + "dependencies": { + "@remix-run/router": "1.19.0", + "react-router": "6.26.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", + "dev": true, + "dependencies": { + "throttleit": "^1.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/swc-loader": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz", + "integrity": "sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==", + "dependencies": { + "@swc/counter": "^0.1.3" + }, + "peerDependencies": { + "@swc/core": "^1.2.147", + "webpack": ">=2" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", + "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/throttleit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", + "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.2.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz", + "integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "ejs": "^3.1.10", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz", + "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", + "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.18.0", + "@typescript-eslint/parser": "7.18.0", + "@typescript-eslint/utils": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.0.1.tgz", + "integrity": "sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==", + "dev": true, + "dependencies": { + "acorn": "^8.8.1", + "chokidar": "^3.5.3", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.5.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/webpack": { + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", + "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/memfs": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", + "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz", + "integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==", + "dev": true + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz", + "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==", + "dependencies": { + "use-sync-external-store": "1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 000000000..6d673dd06 --- /dev/null +++ b/client/package.json @@ -0,0 +1,85 @@ +{ + "name": "haengdong-client", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "prod": "NODE_ENV=production webpack server --open --config webpack.prod.mjs", + "dev": "NODE_ENV=development webpack server --open --config webpack.dev.mjs", + "build": "NODE_ENV=production webpack --config webpack.prod.mjs", + "build-dev": "NODE_ENV=development webpack --config webpack.dev.mjs", + "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", + "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'", + "cypress-open": "cypress open", + "cypress-run": "cypress run", + "test": "jest" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@eslint/compat": "^1.1.0", + "@eslint/js": "^9.6.0", + "@jest/types": "^29.6.3", + "@sentry/webpack-plugin": "^2.22.0", + "@svgr/webpack": "^8.1.0", + "@tanstack/react-query-devtools": "^5.52.0", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.4.8", + "@testing-library/react": "^16.0.0", + "@types/dotenv-webpack": "^7.0.7", + "@types/jest": "^29.5.12", + "@types/react": "^18.3.3", + "@types/react-copy-to-clipboard": "^5.0.7", + "@types/react-dom": "^18.3.0", + "@types/testing-library__jest-dom": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^7.16.0", + "@typescript-eslint/parser": "^7.16.0", + "cypress": "^13.13.2", + "dotenv-webpack": "^8.1.0", + "eslint": "^9.6.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-react": "^7.34.3", + "eslint-plugin-react-hooks": "^4.6.2", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "globals": "^15.8.0", + "html-loader": "^5.0.0", + "html-webpack-plugin": "^5.6.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jsdom": "^24.1.1", + "modify-source-webpack-plugin": "^4.1.0", + "msw": "^2.3.5", + "prettier": "3.3.2", + "ts-jest": "^29.2.4", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "typescript": "^5.5.4", + "typescript-eslint": "^7.16.0", + "undici": "^5.28.4", + "webpack": "^5.93.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.0.4", + "webpack-merge": "^6.0.1" + }, + "dependencies": { + "@emotion/react": "^11.11.4", + "@sentry/react": "^8.25.0", + "@tanstack/react-query": "^5.51.23", + "haengdong-design": "^0.1.81", + "jest-canvas-mock": "^2.5.2", + "react": "^18.3.1", + "react-copy-to-clipboard": "^5.1.0", + "react-dom": "^18.3.1", + "react-error-boundary": "^4.0.13", + "react-router-dom": "^6.24.1", + "zustand": "^4.5.5" + }, + "engines": { + "npm": ">=10.7.0", + "node": ">=20.15.1" + } +} diff --git a/client/public/mockServiceWorker.js b/client/public/mockServiceWorker.js new file mode 100644 index 000000000..3abd19a06 --- /dev/null +++ b/client/public/mockServiceWorker.js @@ -0,0 +1,281 @@ +/* eslint-disable */ +/* tslint:disable */ + +/** + * Mock Service Worker. + * @see https://github.com/mswjs/msw + * - Please do NOT modify this file. + * - Please do NOT serve this file on production. + */ + +const PACKAGE_VERSION = '2.3.5'; +const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'; +const IS_MOCKED_RESPONSE = Symbol('isMockedResponse'); +const activeClientIds = new Set(); + +self.addEventListener('install', function () { + self.skipWaiting(); +}); + +self.addEventListener('activate', function (event) { + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener('message', async function (event) { + const clientId = event.source.id; + + if (!clientId || !self.clients) { + return; + } + + const client = await self.clients.get(clientId); + + if (!client) { + return; + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }); + + switch (event.data) { + case 'KEEPALIVE_REQUEST': { + sendToClient(client, { + type: 'KEEPALIVE_RESPONSE', + }); + break; + } + + case 'INTEGRITY_CHECK_REQUEST': { + sendToClient(client, { + type: 'INTEGRITY_CHECK_RESPONSE', + payload: { + packageVersion: PACKAGE_VERSION, + checksum: INTEGRITY_CHECKSUM, + }, + }); + break; + } + + case 'MOCK_ACTIVATE': { + activeClientIds.add(clientId); + + sendToClient(client, { + type: 'MOCKING_ENABLED', + payload: true, + }); + break; + } + + case 'MOCK_DEACTIVATE': { + activeClientIds.delete(clientId); + break; + } + + case 'CLIENT_CLOSED': { + activeClientIds.delete(clientId); + + const remainingClients = allClients.filter(client => { + return client.id !== clientId; + }); + + // Unregister itself when there are no more clients + if (remainingClients.length === 0) { + self.registration.unregister(); + } + + break; + } + } +}); + +self.addEventListener('fetch', function (event) { + const {request} = event; + + // Bypass navigation requests. + if (request.mode === 'navigate') { + return; + } + + // Opening the DevTools triggers the "only-if-cached" request + // that cannot be handled by the worker. Bypass such requests. + if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { + return; + } + + // Bypass all requests when there are no active clients. + // Prevents the self-unregistered worked from handling requests + // after it's been deleted (still remains active until the next reload). + if (activeClientIds.size === 0) { + return; + } + + // Generate unique request ID. + const requestId = crypto.randomUUID(); + event.respondWith(handleRequest(event, requestId)); +}); + +async function handleRequest(event, requestId) { + const client = await resolveMainClient(event); + const response = await getResponse(event, client, requestId); + + // Send back the response clone for the "response:*" life-cycle events. + // Ensure MSW is active and ready to handle the message, otherwise + // this message will pend indefinitely. + if (client && activeClientIds.has(client.id)) { + (async function () { + const responseClone = response.clone(); + + sendToClient( + client, + { + type: 'RESPONSE', + payload: { + requestId, + isMockedResponse: IS_MOCKED_RESPONSE in response, + type: responseClone.type, + status: responseClone.status, + statusText: responseClone.statusText, + body: responseClone.body, + headers: Object.fromEntries(responseClone.headers.entries()), + }, + }, + [responseClone.body], + ); + })(); + } + + return response; +} + +// Resolve the main client for the given event. +// Client that issues a request doesn't necessarily equal the client +// that registered the worker. It's with the latter the worker should +// communicate with during the response resolving phase. +async function resolveMainClient(event) { + const client = await self.clients.get(event.clientId); + + if (client?.frameType === 'top-level') { + return client; + } + + const allClients = await self.clients.matchAll({ + type: 'window', + }); + + return allClients + .filter(client => { + // Get only those clients that are currently visible. + return client.visibilityState === 'visible'; + }) + .find(client => { + // Find the client ID that's recorded in the + // set of clients that have registered the worker. + return activeClientIds.has(client.id); + }); +} + +async function getResponse(event, client, requestId) { + const {request} = event; + + // Clone the request because it might've been already used + // (i.e. its body has been read and sent to the client). + const requestClone = request.clone(); + + function passthrough() { + const headers = Object.fromEntries(requestClone.headers.entries()); + + // Remove internal MSW request header so the passthrough request + // complies with any potential CORS preflight checks on the server. + // Some servers forbid unknown request headers. + delete headers['x-msw-intention']; + + return fetch(requestClone, {headers}); + } + + // Bypass mocking when the client is not active. + if (!client) { + return passthrough(); + } + + // Bypass initial page load requests (i.e. static assets). + // The absence of the immediate/parent client in the map of the active clients + // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet + // and is not ready to handle requests. + if (!activeClientIds.has(client.id)) { + return passthrough(); + } + + // Notify the client that a request has been intercepted. + const requestBuffer = await request.arrayBuffer(); + const clientMessage = await sendToClient( + client, + { + type: 'REQUEST', + payload: { + id: requestId, + url: request.url, + mode: request.mode, + method: request.method, + headers: Object.fromEntries(request.headers.entries()), + cache: request.cache, + credentials: request.credentials, + destination: request.destination, + integrity: request.integrity, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + body: requestBuffer, + keepalive: request.keepalive, + }, + }, + [requestBuffer], + ); + + switch (clientMessage.type) { + case 'MOCK_RESPONSE': { + return respondWithMock(clientMessage.data); + } + + case 'PASSTHROUGH': { + return passthrough(); + } + } + + return passthrough(); +} + +function sendToClient(client, message, transferrables = []) { + return new Promise((resolve, reject) => { + const channel = new MessageChannel(); + + channel.port1.onmessage = event => { + if (event.data && event.data.error) { + return reject(event.data.error); + } + + resolve(event.data); + }; + + client.postMessage(message, [channel.port2].concat(transferrables.filter(Boolean))); + }); +} + +async function respondWithMock(response) { + // Setting response status code to 0 is a no-op. + // However, when responding with a "Response.error()", the produced Response + // instance will have status code set to 0. Since it's not possible to create + // a Response instance with status code 0, handle that use-case separately. + if (response.status === 0) { + return Response.error(); + } + + const mockedResponse = new Response(response.body, response); + + Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { + value: true, + enumerable: true, + }); + + return mockedResponse; +} diff --git a/client/src/App.tsx b/client/src/App.tsx new file mode 100644 index 000000000..4e9ce39e1 --- /dev/null +++ b/client/src/App.tsx @@ -0,0 +1,31 @@ +import {Outlet} from 'react-router-dom'; +import {HDesignProvider} from 'haengdong-design'; +import {Global} from '@emotion/react'; +import {ReactQueryDevtools} from '@tanstack/react-query-devtools'; + +import {ToastProvider} from '@hooks/useToast/ToastProvider'; +import QueryClientBoundary from '@components/QueryClientBoundary/QueryClientBoundary'; +import ErrorCatcher from '@components/AppErrorBoundary/ErrorCatcher'; + +import {GlobalStyle} from './GlobalStyle'; +import UnhandledErrorBoundary from './UnhandledErrorBoundary'; + +const App: React.FC = () => { + return ( + + + + + + + + + + + + + + ); +}; + +export default App; diff --git a/client/src/GlobalStyle.ts b/client/src/GlobalStyle.ts new file mode 100644 index 000000000..ab16de8e1 --- /dev/null +++ b/client/src/GlobalStyle.ts @@ -0,0 +1,160 @@ +import {css} from '@emotion/react'; + +// reset css -> index css +export const GlobalStyle = css` + html, + body, + div, + span, + applet, + object, + iframe, + h1, + h2, + h3, + h4, + h5, + h6, + p, + blockquote, + pre, + a, + abbr, + acronym, + address, + big, + cite, + code, + del, + dfn, + em, + img, + ins, + kbd, + q, + s, + samp, + small, + strike, + strong, + sub, + sup, + tt, + b, + u, + i, + center, + dl, + dt, + dd, + ol, + ul, + li, + fieldset, + form, + label, + legend, + table, + caption, + tbody, + tfoot, + thead, + tr, + th, + td, + article, + aside, + canvas, + details, + embed, + figure, + figcaption, + footer, + header, + hgroup, + menu, + nav, + output, + ruby, + section, + summary, + time, + mark, + audio, + video { + vertical-align: baseline; + margin: 0; + border: 0; + padding: 0; + font-size: 100%; + font: inherit; + } + /* HTML5 display-role reset for older browsers */ + article, + aside, + details, + figcaption, + figure, + footer, + header, + hgroup, + menu, + nav, + section { + display: block; + } + body { + line-height: 1; + } + ol, + ul { + list-style: none; + } + blockquote, + q { + quotes: none; + } + blockquote:before, + blockquote:after, + q:before, + q:after { + content: ''; + content: none; + } + table { + border-collapse: collapse; + border-spacing: 0; + } + button { + cursor: pointer; + border: none; + background-color: transparent; + } + * { + box-sizing: border-box; + } + + html { + height: 100%; + } + + body { + max-width: 768px; + height: 100%; + margin: 0 auto; + + overflow-y: scroll; + &::-webkit-scrollbar { + display: none; + } + } + + section { + width: 100%; + } + + #root { + display: flex; + flex-direction: column; + } +`; diff --git a/client/src/UnhandledErrorBoundary.tsx b/client/src/UnhandledErrorBoundary.tsx new file mode 100644 index 000000000..78d017344 --- /dev/null +++ b/client/src/UnhandledErrorBoundary.tsx @@ -0,0 +1,10 @@ +import {StrictPropsWithChildren} from 'haengdong-design/dist/type/strictPropsWithChildren'; +import {ErrorBoundary} from 'react-error-boundary'; + +import ErrorPage from '@pages/ErrorPage/ErrorPage'; + +const UnhandledErrorBoundary = ({children}: StrictPropsWithChildren) => { + return }>{children}; +}; + +export default UnhandledErrorBoundary; diff --git a/client/src/apis/baseUrl.ts b/client/src/apis/baseUrl.ts new file mode 100644 index 000000000..37fc00a94 --- /dev/null +++ b/client/src/apis/baseUrl.ts @@ -0,0 +1,3 @@ +export const BASE_URL = { + HD: process.env.API_BASE_URL, +}; diff --git a/client/src/apis/fetcher.ts b/client/src/apis/fetcher.ts new file mode 100644 index 000000000..2e1c2d067 --- /dev/null +++ b/client/src/apis/fetcher.ts @@ -0,0 +1,120 @@ +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; + +import objectToQueryString from '@utils/objectToQueryString'; + +import {UNKNOWN_ERROR} from '@constants/errorMessage'; + +import FetchError from '../errors/FetchError'; + +export type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; + +type Body = ReadableStream | XMLHttpRequestBodyInit; +type HeadersType = [string, string][] | Record | Headers; + +export type ObjectQueryParams = Record; + +type RequestProps = { + baseUrl?: string; + endpoint: string; + headers?: HeadersType; + body?: Body | object | null; + queryParams?: ObjectQueryParams; +}; + +type FetcherProps = RequestProps & { + method: Method; +}; + +type Options = { + method: Method; + headers: HeadersType; + body?: Body | null; +}; + +type ErrorHandlerProps = { + url: string; + options: Options; + body: string; +}; + +const API_BASE_URL = process.env.API_BASE_URL ?? ''; + +export const requestGet = async ({headers = {}, ...args}: RequestProps): Promise => { + const response = await fetcher({ + ...args, + method: 'GET', + headers, + }); + + const data: T = await response!.json(); + return data; +}; + +export const requestPatch = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'PATCH', headers, ...args}); +}; + +export const requestPut = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'PUT', headers, ...args}); +}; + +export const requestPostWithoutResponse = async ({headers = {}, ...args}: RequestProps) => { + await fetcher({method: 'POST', headers, ...args}); +}; + +export const requestPostWithResponse = async ({headers = {}, ...args}: RequestProps): Promise => { + const response = await fetcher({method: 'POST', headers, ...args}); + + const data: T = await response!.json(); + return data; +}; + +export const requestDelete = ({headers = {}, ...args}: RequestProps) => { + return fetcher({method: 'DELETE', headers, ...args}); +}; + +const fetcher = ({baseUrl = API_BASE_URL, method, endpoint, headers, body, queryParams}: FetcherProps) => { + const options = { + method, + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + ...headers, + }, + body: body ? JSON.stringify(body) : null, + }; + + let url = `${baseUrl}${endpoint}`; + + if (queryParams) url += `?${objectToQueryString(queryParams)}`; + + return errorHandler({url, options, body: JSON.stringify(body)}); +}; + +const errorHandler = async ({url, options, body}: ErrorHandlerProps) => { + try { + const response: Response = await fetch(url, options); + + if (!response.ok) { + const serverErrorInfo: ErrorInfo = await response.json(); + + throw new FetchError({ + status: response.status, + requestBody: body, + endpoint: response.url, + errorInfo: serverErrorInfo, + name: serverErrorInfo.errorCode, + message: serverErrorInfo.message || '', + method: options.method, + }); + } + + return response; + } catch (error) { + if (error instanceof Error) { + throw error; // 그대로 FetchError || Error 인스턴스를 던집니다. + } + + throw new Error(UNKNOWN_ERROR); + } +}; diff --git a/client/src/apis/request/auth.ts b/client/src/apis/request/auth.ts new file mode 100644 index 000000000..9c56d1f6b --- /dev/null +++ b/client/src/apis/request/auth.ts @@ -0,0 +1,25 @@ +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestPostWithoutResponse} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +export type RequestToken = { + password: string; +}; + +export const requestPostAuthentication = async ({eventId}: WithEventId) => { + await requestPostWithoutResponse({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/auth`, + }); +}; + +export const requestPostToken = async ({eventId, password}: WithEventId) => { + await requestPostWithoutResponse({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/login`, + body: { + password: password, + }, + }); +}; diff --git a/client/src/apis/request/bill.ts b/client/src/apis/request/bill.ts new file mode 100644 index 000000000..c08168520 --- /dev/null +++ b/client/src/apis/request/bill.ts @@ -0,0 +1,69 @@ +import type {Bill, MemberReportInAction} from 'types/serviceType'; + +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestDelete, requestGet, requestPostWithoutResponse, requestPut} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +type RequestPostBillList = { + billList: Bill[]; +}; + +export const requestPostBillList = async ({eventId, billList}: WithEventId) => { + await requestPostWithoutResponse({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions`, + body: { + actions: billList, + }, + }); +}; + +type RequestBillAction = { + actionId: number; +}; + +export const requestDeleteBillAction = async ({eventId, actionId}: WithEventId) => { + await requestDelete({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}`, + }); +}; + +type RequestPutBillAction = Bill & RequestBillAction; + +export const requestPutBillAction = async ({eventId, actionId, title, price}: WithEventId) => { + await requestPut({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}`, + body: { + title, + price, + }, + }); +}; + +export type MemberReportList = {members: MemberReportInAction[]}; + +export const requestGetMemberReportListInAction = async ({eventId, actionId}: WithEventId) => { + return requestGet({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}/fixed`, + }); +}; + +type RequestPutMemberReportList = RequestBillAction & MemberReportList; + +export const requestPutMemberReportListInAction = async ({ + eventId, + actionId, + members, +}: WithEventId) => { + return requestPut({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/bill-actions/${actionId}/fixed`, + body: { + members, + }, + }); +}; diff --git a/client/src/apis/request/event.ts b/client/src/apis/request/event.ts new file mode 100644 index 000000000..c9299c813 --- /dev/null +++ b/client/src/apis/request/event.ts @@ -0,0 +1,32 @@ +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet, requestPostWithResponse} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +export type RequestPostNewEvent = { + eventName: string; + password: number; +}; + +export type ResponsePostNewEvent = { + eventId: string; +}; + +export const requestPostNewEvent = async ({eventName, password}: RequestPostNewEvent) => { + return await requestPostWithResponse({ + endpoint: TEMP_PREFIX, + body: { + eventName: eventName, + password: password, + }, + }); +}; + +type ResponseGetEventName = { + eventName: string; +}; + +export const requestGetEventName = async ({eventId}: WithEventId) => { + return requestGet({ + endpoint: `${TEMP_PREFIX}/${eventId}`, + }); +}; diff --git a/client/src/apis/request/member.ts b/client/src/apis/request/member.ts new file mode 100644 index 000000000..dd7152575 --- /dev/null +++ b/client/src/apis/request/member.ts @@ -0,0 +1,84 @@ +import type {MemberType} from 'types/serviceType'; + +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestDelete, requestGet, requestPut, requestPostWithoutResponse} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +type RequestPostMemberList = { + memberNameList: string[]; + type: MemberType; +}; + +export const requestPostMemberList = async ({eventId, type, memberNameList}: WithEventId) => { + await requestPostWithoutResponse({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/member-actions`, + body: { + members: memberNameList, + status: type, + }, + }); +}; + +type RequestDeleteMemberAction = { + actionId: number; +}; + +export const requestDeleteMemberAction = async ({eventId, actionId}: WithEventId) => { + await requestDelete({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/member-actions/${actionId}`, + }); +}; + +type ResponseGetAllMemberList = { + memberNames: string[]; +}; + +export const requestGetAllMemberList = async ({eventId}: WithEventId) => { + return requestGet({ + endpoint: `${TEMP_PREFIX}/${eventId}/members`, + }); +}; + +export type MemberChange = { + before: string; + after: string; +}; + +type RequestPutAllMemberList = { + members: MemberChange[]; +}; + +export const requestPutAllMemberList = async ({eventId, members}: WithEventId) => { + await requestPut({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/members/nameChange`, + body: { + members, + }, + }); +}; + +type RequestDeleteAllMemberList = { + memberName: string; +}; + +export const requestDeleteAllMemberList = async ({eventId, memberName}: WithEventId) => { + await requestDelete({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/members/${memberName}`, + }); +}; + +export type ResponseGetCurrentInMemberList = { + memberNames: string[]; +}; + +export const requestGetCurrentInMemberList = async ({eventId}: WithEventId) => { + return await requestGet({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/members/current`, + }); +}; diff --git a/client/src/apis/request/report.ts b/client/src/apis/request/report.ts new file mode 100644 index 000000000..8992f9c30 --- /dev/null +++ b/client/src/apis/request/report.ts @@ -0,0 +1,19 @@ +import type {MemberReport} from 'types/serviceType'; + +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +type ResponseGetMemberReportList = { + reports: MemberReport[]; +}; + +export const requestGetMemberReportList = async ({eventId}: WithEventId) => { + const {reports} = await requestGet({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions/reports`, + }); + + return reports; +}; diff --git a/client/src/apis/request/stepList.ts b/client/src/apis/request/stepList.ts new file mode 100644 index 000000000..0d47ab90e --- /dev/null +++ b/client/src/apis/request/stepList.ts @@ -0,0 +1,17 @@ +import type {StepList} from 'types/serviceType'; + +import {BASE_URL} from '@apis/baseUrl'; +import {TEMP_PREFIX} from '@apis/tempPrefix'; +import {requestGet} from '@apis/fetcher'; +import {WithEventId} from '@apis/withEventId.type'; + +// TODO: (@weadie) 현재 토큰을 어떻게 관리할지.. 계속 사용되는데 +export const requestGetStepList = async ({eventId}: WithEventId) => { + // TODO: (@weadie) response가 어떻게 오는지 안나와서 data로만 써뒀어요. + const {steps} = await requestGet({ + baseUrl: BASE_URL.HD, + endpoint: `${TEMP_PREFIX}/${eventId}/actions`, + }); + + return steps; +}; diff --git a/client/src/apis/tempPrefix.ts b/client/src/apis/tempPrefix.ts new file mode 100644 index 000000000..949981b73 --- /dev/null +++ b/client/src/apis/tempPrefix.ts @@ -0,0 +1,2 @@ +// TODO: (@weadie) 반복되서 쓰이는 이 api/events가 추후 수정 가능성이 있어서 일단 편집하기 편하게 이 변수를 재사용하도록 했습니다. +export const TEMP_PREFIX = '/api/events'; diff --git a/client/src/apis/withEventId.type.ts b/client/src/apis/withEventId.type.ts new file mode 100644 index 000000000..b88160e3e --- /dev/null +++ b/client/src/apis/withEventId.type.ts @@ -0,0 +1,3 @@ +export type WithEventId

= P & { + eventId: string; +}; diff --git a/client/src/assets/image/addBillMockup.svg b/client/src/assets/image/addBillMockup.svg new file mode 100644 index 000000000..c7e4aa109 --- /dev/null +++ b/client/src/assets/image/addBillMockup.svg @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/assets/image/addMemberMockup.svg b/client/src/assets/image/addMemberMockup.svg new file mode 100644 index 000000000..1bf5892d3 --- /dev/null +++ b/client/src/assets/image/addMemberMockup.svg @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/assets/image/chevronDownLarge.svg b/client/src/assets/image/chevronDownLarge.svg new file mode 100644 index 000000000..11a631f88 --- /dev/null +++ b/client/src/assets/image/chevronDownLarge.svg @@ -0,0 +1,3 @@ + + + diff --git a/client/src/assets/image/dog.svg b/client/src/assets/image/dog.svg new file mode 100644 index 000000000..f70558ed6 --- /dev/null +++ b/client/src/assets/image/dog.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/assets/image/heundeut.svg b/client/src/assets/image/heundeut.svg new file mode 100644 index 000000000..c78ca8c9b --- /dev/null +++ b/client/src/assets/image/heundeut.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/assets/image/memberReportMockup.svg b/client/src/assets/image/memberReportMockup.svg new file mode 100644 index 000000000..efbaf3c1c --- /dev/null +++ b/client/src/assets/image/memberReportMockup.svg @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/assets/image/runningDog.svg b/client/src/assets/image/runningDog.svg new file mode 100644 index 000000000..60951e642 --- /dev/null +++ b/client/src/assets/image/runningDog.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/client/src/assets/image/standingDog.svg b/client/src/assets/image/standingDog.svg new file mode 100644 index 000000000..2d34a8cf9 --- /dev/null +++ b/client/src/assets/image/standingDog.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx b/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx new file mode 100644 index 000000000..8d7946b8a --- /dev/null +++ b/client/src/components/AppErrorBoundary/ErrorCatcher.test.tsx @@ -0,0 +1,92 @@ +import {render, screen, waitFor} from '@testing-library/react'; +import {act, ReactNode} from 'react'; +import {MemoryRouter} from 'react-router-dom'; +import {HDesignProvider} from 'haengdong-design'; + +import FetchError from '@errors/FetchError'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; + +import {useAppErrorStore} from '@store/appErrorStore'; + +import {SERVER_ERROR_MESSAGES} from '@constants/errorMessage'; + +import UnhandledErrorBoundary from '../../UnhandledErrorBoundary'; + +import ErrorCatcher from './ErrorCatcher'; + +// 테스트용 헬퍼 컴포넌트 +const TestComponent = ({triggerError}: {triggerError: () => void}) => { + return ; +}; + +const setup = (ui: ReactNode) => + render( + + + + + {ui} + + + + , + ); + +describe('ErrorCatcher', () => { + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: jest.fn(), + })); + + it('핸들링 가능한 에러인 경우 토스트가 표시된다.', async () => { + const errorCode = 'EVENT_NOT_FOUND'; + const error = new FetchError({ + errorInfo: {errorCode, message: '서버의 에러메세지'}, + name: errorCode, + message: '에러메세지', + status: 200, + endpoint: '', + method: 'GET', + requestBody: '', + }); + + const {updateAppError} = useAppErrorStore.getState(); + + setup( updateAppError(error)} />); + + act(() => { + screen.getByText('Trigger Error').click(); + }); + + const errorMessage = SERVER_ERROR_MESSAGES[errorCode]; + + await waitFor(() => { + expect(screen.getByText(errorMessage)).toBeInTheDocument(); + }); + }); + + it('핸들링 불가능한 에러인 경우 에러 바운더리가 표시된다.', async () => { + const errorCode = '모르겠는 에러'; + const error = new FetchError({ + errorInfo: {errorCode, message: '모르겠는 에러메세지'}, + name: errorCode, + message: '에러메세지', + status: 400, + endpoint: '', + method: 'GET', + requestBody: '', + }); + + const {updateAppError} = useAppErrorStore.getState(); + + setup( updateAppError(error)} />); + + act(() => { + screen.getByText('Trigger Error').click(); + }); + + await waitFor(() => { + expect(screen.getByText('알 수 없는 오류입니다.')).toBeInTheDocument(); + }); + }); +}); diff --git a/client/src/components/AppErrorBoundary/ErrorCatcher.tsx b/client/src/components/AppErrorBoundary/ErrorCatcher.tsx new file mode 100644 index 000000000..dde5f3d64 --- /dev/null +++ b/client/src/components/AppErrorBoundary/ErrorCatcher.tsx @@ -0,0 +1,62 @@ +import {useEffect} from 'react'; + +import FetchError from '@errors/FetchError'; +import {useToast} from '@hooks/useToast/useToast'; + +import {useAppErrorStore} from '@store/appErrorStore'; + +import {captureError} from '@utils/captureError'; + +import {SERVER_ERROR_MESSAGES, UNKNOWN_ERROR} from '@constants/errorMessage'; + +export type ErrorInfo = { + errorCode: string; + message: string; +}; + +const convertAppErrorToErrorInfo = (appError: Error) => { + if (appError instanceof Error) { + const errorInfo = + appError instanceof FetchError ? appError.errorInfo : {errorCode: appError.name, message: appError.message}; + + return errorInfo; + } else { + const errorInfo = {errorCode: UNKNOWN_ERROR, message: JSON.stringify(appError)}; + + return errorInfo; + } +}; + +const isUnhandledError = (errorInfo: ErrorInfo) => { + if (errorInfo.errorCode === 'INTERNAL_SERVER_ERROR') return true; + + return SERVER_ERROR_MESSAGES[errorInfo.errorCode] === undefined; +}; + +const ErrorCatcher = ({children}: React.PropsWithChildren) => { + const {appError} = useAppErrorStore(); + const {showToast} = useToast(); + + useEffect(() => { + if (appError) { + const errorInfo = convertAppErrorToErrorInfo(appError); + captureError(appError, errorInfo); + + if (!isUnhandledError(errorInfo)) { + showToast({ + showingTime: 3000, + message: SERVER_ERROR_MESSAGES[errorInfo.errorCode], + type: 'error', + position: 'bottom', + bottom: '8rem', + }); + } else { + throw appError; + } + } + }, [appError]); + + return children; +}; + +export default ErrorCatcher; diff --git a/client/src/components/Common/Logo/Logo.style.ts b/client/src/components/Common/Logo/Logo.style.ts new file mode 100644 index 000000000..89f97ede0 --- /dev/null +++ b/client/src/components/Common/Logo/Logo.style.ts @@ -0,0 +1,8 @@ +import {css} from '@emotion/react'; + +export const logoStyle = css({ + display: 'flex', + justifyContent: 'center', + + width: '100%', +}); diff --git a/client/src/components/Common/Logo/RunningDogLogo.tsx b/client/src/components/Common/Logo/RunningDogLogo.tsx new file mode 100644 index 000000000..a09a904c1 --- /dev/null +++ b/client/src/components/Common/Logo/RunningDogLogo.tsx @@ -0,0 +1,13 @@ +import RunningDog from '@assets/image/runningDog.svg'; + +import {logoStyle} from './Logo.style'; + +const RunningDogLogo = () => { + return ( +

+ +
+ ); +}; + +export default RunningDogLogo; diff --git a/client/src/components/Common/Logo/StandingDogLogo.tsx b/client/src/components/Common/Logo/StandingDogLogo.tsx new file mode 100644 index 000000000..5c2cf591e --- /dev/null +++ b/client/src/components/Common/Logo/StandingDogLogo.tsx @@ -0,0 +1,13 @@ +import StandingDog from '@assets/image/standingDog.svg'; + +import {logoStyle} from './Logo.style'; + +const StandingDogLogo = () => { + return ( +
+ +
+ ); +}; + +export default StandingDogLogo; diff --git a/client/src/components/Common/Logo/index.ts b/client/src/components/Common/Logo/index.ts new file mode 100644 index 000000000..43a08fd54 --- /dev/null +++ b/client/src/components/Common/Logo/index.ts @@ -0,0 +1,2 @@ +export {default as StandingDog} from './StandingDogLogo'; +export {default as RunningDog} from './RunningDogLogo'; diff --git a/client/src/components/MemberReportList/MemberReportList.tsx b/client/src/components/MemberReportList/MemberReportList.tsx new file mode 100644 index 000000000..1004540fa --- /dev/null +++ b/client/src/components/MemberReportList/MemberReportList.tsx @@ -0,0 +1,22 @@ +import {ExpenseList, Flex, Input} from 'haengdong-design'; +import React, {useState} from 'react'; + +import useSearchMemberReportList from '@hooks/useSearchMemberReportList/useSearchMemberReportList'; + +const MemberReportList = () => { + const [name, setName] = useState(''); + const {memberReportSearchList} = useSearchMemberReportList({name}); + + const changeName = ({target}: React.ChangeEvent) => { + setName(target.value); + }; + + return ( + + + + + ); +}; + +export default MemberReportList; diff --git a/client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx b/client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx new file mode 100644 index 000000000..645acb468 --- /dev/null +++ b/client/src/components/Modal/ExpenseDetailModal/ExpenseDetailModal.tsx @@ -0,0 +1,142 @@ +import type {BillAction} from 'types/serviceType'; + +import {BottomSheet, EditableItem, FixedButton, Flex, Text} from 'haengdong-design'; + +import validatePurchase from '@utils/validate/validatePurchase'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import useMemberReportListInAction from '@hooks/useMemberReportListInAction/useMemberReportListInAction'; +import useMemberReportInput from '@hooks/useMemberReportListInAction/useMemberReportInput'; + +import usePutAndDeleteBillAction from '@hooks/usePutAndDeleteBillAction'; + +import { + bottomSheetHeaderStyle, + bottomSheetStyle, + inputContainerStyle, +} from '../SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style'; + +type PutAndDeleteBillActionModalProps = { + billAction: BillAction; + isBottomSheetOpened: boolean; + setIsBottomSheetOpened: React.Dispatch>; +}; + +const ExpenseDetailModal = ({ + billAction, + isBottomSheetOpened, + setIsBottomSheetOpened, +}: PutAndDeleteBillActionModalProps) => { + const { + inputPair, + handleInputChange, + // handleOnBlur, + // errorMessage, + // errorInfo, + canSubmit, + onDelete, + onSubmit: putBillAction, + } = usePutAndDeleteBillAction( + {title: billAction.name, price: String(billAction.price), index: 0}, + validatePurchase, + () => setIsBottomSheetOpened(false), + ); + + const { + memberReportListInAction, + addAdjustedMember, + onSubmit: putMemberReportListInAction, + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + isExistAdjustedPrice, + } = useMemberReportListInAction(billAction.actionId, Number(inputPair.price), () => setIsBottomSheetOpened(false)); + const { + inputList, + onChange, + canEditList, + canSubmit: isChangedMemberReportInput, + } = useMemberReportInput({ + data: memberReportListInAction, + addAdjustedMember, + totalPrice: Number(inputPair.price), + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + }); + + const {data: stepListData = []} = useRequestGetStepList(); + + const actionMemberList = stepListData.filter(({actions}) => + actions.find(({actionId}) => actionId === billAction.actionId), + )[0].members; + + return ( + setIsBottomSheetOpened(false)}> +
setIsBottomSheetOpened(false)}> +

+ 지출 내역 상세 +

+
+ + ) => handleInputChange('title', event)} + disabled + /> + + ) => handleInputChange('price', event)} + isFixed={isExistAdjustedPrice()} + disabled + /> + + + + + + + {inputList.map(({name, price, isFixed}, index) => ( + + + + onChange(event, index)} + isFixed={isFixed} + textSize="smallBody" + value={price} + placeholder="0" + type="number" + disabled + style={{textAlign: 'right'}} + > + + + + ))} + + +
+ + 닫기 + +
+
+ ); +}; + +export default ExpenseDetailModal; diff --git a/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts new file mode 100644 index 000000000..4bbefdba9 --- /dev/null +++ b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.style.ts @@ -0,0 +1,10 @@ +import {css} from '@emotion/react'; + +export const bottomSheetStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1.5rem', +}); diff --git a/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx new file mode 100644 index 000000000..e3579ab6b --- /dev/null +++ b/client/src/components/Modal/MemberListInBillStep/MemberListInBillStep.tsx @@ -0,0 +1,53 @@ +import type {MemberReport} from 'types/serviceType'; + +import {BottomSheet, FixedButton, Flex, Text} from 'haengdong-design'; + +import {bottomSheetStyle} from './MemberListInBillStep.style'; + +type MemberListInBillStepProps = { + stepName: string; + memberList: MemberReport[]; + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +}; + +const MemberListInBillStep = ({ + stepName, + memberList, + isOpenBottomSheet, + setIsOpenBottomSheet, +}: MemberListInBillStepProps) => { + const closeModal = () => setIsOpenBottomSheet(false); + + return ( + +
+ + {`${stepName} 참석자`} + {`총 ${memberList.length}명`} + + +
    + {memberList.map(member => ( +
  • + + + {member.name} + + + {`${member.price.toLocaleString('ko-kr')} 원`} + + +
  • + ))} +
+
+
+ + 닫기 + +
+ ); +}; + +export default MemberListInBillStep; diff --git a/client/src/components/Modal/MemberListInBillStep/index.ts b/client/src/components/Modal/MemberListInBillStep/index.ts new file mode 100644 index 000000000..137df8c87 --- /dev/null +++ b/client/src/components/Modal/MemberListInBillStep/index.ts @@ -0,0 +1 @@ +export {default as MemberListInBillStep} from './MemberListInBillStep'; diff --git a/client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx b/client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx new file mode 100644 index 000000000..51e33589b --- /dev/null +++ b/client/src/components/Modal/ModalBasedOnMemberCount/ModalBasedOnMemberCount.tsx @@ -0,0 +1,39 @@ +import {SetAllMemberListModal, SetInitialMemberListModal, SetActionListModal} from '@components/Modal/index'; + +interface ModalBasedOnMemberCountProps { + allMemberList: string[]; + isOpenBottomSheet: boolean; + isOpenAllMemberListButton: boolean; + setIsOpenBottomSheet: React.Dispatch>; + setIsOpenAllMemberListButton: React.Dispatch>; +} + +const ModalBasedOnMemberCount = ({ + allMemberList, + isOpenBottomSheet, + isOpenAllMemberListButton, + setIsOpenBottomSheet, + setIsOpenAllMemberListButton, +}: ModalBasedOnMemberCountProps) => { + if (isOpenAllMemberListButton) { + return ( + + ); + } + switch (allMemberList.length) { + case 0: + return ( + + ); + + default: + return ; + } +}; + +export default ModalBasedOnMemberCount; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts new file mode 100644 index 000000000..7fad2e001 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.style.ts @@ -0,0 +1,23 @@ +import {css} from '@emotion/react'; + +const container = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + height: '100%', +}); + +const inputGroup = css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '14rem', +}); + +const addMemberActionListModalContentStyle = { + container, + inputGroup, +}; + +export default addMemberActionListModalContentStyle; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx new file mode 100644 index 000000000..ad6e63f28 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/AddMemberActionListModalContent.tsx @@ -0,0 +1,50 @@ +import type {MemberType} from 'types/serviceType'; + +import {FixedButton, LabelGroupInput} from 'haengdong-design'; + +import validateMemberName from '@utils/validate/validateMemberName'; +import useRequestPostMemberList from '@hooks/queries/useRequestPostMemberList'; + +import useDynamicInput from '@hooks/useDynamicInput'; + +import style from './AddMemberActionListModalContent.style'; +import InMember from './InMember'; +import OutMember from './OutMember'; + +interface AddMemberActionListModalContentProps { + inOutAction: MemberType; + setIsOpenBottomSheet: React.Dispatch>; +} + +const AddMemberActionListModalContent = ({inOutAction, setIsOpenBottomSheet}: AddMemberActionListModalContentProps) => { + const dynamicProps = useDynamicInput(validateMemberName); + const {inputList, getFilledInputList, errorMessage, canSubmit, resetInputValue} = dynamicProps; + + const {mutate: postMemberList} = useRequestPostMemberList(); + + const handleUpdateMemberListSubmit = () => { + postMemberList({memberNameList: getFilledInputList().map(({value}) => value), type: inOutAction}); + setIsOpenBottomSheet(false); + }; + + return ( +
+
+ + {inOutAction === 'IN' ? : } + +
+ { + handleUpdateMemberListSubmit(); + resetInputValue(); + }} + /> +
+ ); +}; + +export default AddMemberActionListModalContent; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx new file mode 100644 index 000000000..5f9f9a2e0 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/InMember.tsx @@ -0,0 +1,35 @@ +import {LabelGroupInput} from 'haengdong-design'; + +import {ReturnUseDynamicInput} from '@hooks/useDynamicInput'; + +interface InMemberProps { + dynamicProps: ReturnUseDynamicInput; +} + +const InMember = ({dynamicProps}: InMemberProps) => { + const { + inputList, + inputRefList, + handleInputChange, + deleteEmptyInputElementOnBlur, + focusNextInputOnEnter, + errorIndexList, + } = dynamicProps; + return inputList.map(({value, index}) => ( + (inputRefList.current[index] = el)} + isError={errorIndexList.includes(index)} + onChange={e => handleInputChange(index, e)} + onBlur={() => deleteEmptyInputElementOnBlur()} + onKeyDown={e => focusNextInputOnEnter(e, index)} + placeholder="이름" + autoFocus={inputList.length === 1 && index === 0} + /> + )); +}; + +export default InMember; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx new file mode 100644 index 000000000..9294b18ae --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/OutMember.tsx @@ -0,0 +1,52 @@ +import {LabelGroupInput, Search} from 'haengdong-design'; + +import {ReturnUseDynamicInput} from '@hooks/useDynamicInput'; +import useSearchInMemberList from '@hooks/useSearchInMemberList'; + +interface OutMemberProps { + dynamicProps: ReturnUseDynamicInput; +} + +const OutMember = ({dynamicProps}: OutMemberProps) => { + const { + inputList, + inputRefList, + errorIndexList, + deleteEmptyInputElementOnBlur, + focusNextInputOnEnter, + handleInputChange, + handleChange, + } = dynamicProps; + const {currentInputIndex, filteredInMemberList, handleCurrentInputIndex, searchCurrentInMember, chooseMember} = + useSearchInMemberList(handleChange); + + const validationAndSearchOnChange = (inputIndex: number, event: React.ChangeEvent) => { + handleCurrentInputIndex(inputIndex); + handleInputChange(inputIndex, event); + searchCurrentInMember(event); + }; + + return inputList.map(({value, index}) => ( + chooseMember(currentInputIndex, term)} + > + (inputRefList.current[index] = el)} + isError={errorIndexList.includes(index)} + onChange={e => validationAndSearchOnChange(index, e)} + onBlur={() => deleteEmptyInputElementOnBlur()} + onKeyDown={e => focusNextInputOnEnter(e, index)} + placeholder="이름" + autoFocus={inputList.length === 1 && index === 0} + /> + + )); +}; + +export default OutMember; diff --git a/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts new file mode 100644 index 000000000..6519283f4 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/AddMemberActionListModalContent/index.ts @@ -0,0 +1 @@ +export {default as AddMemberActionListModalContent} from './AddMemberActionListModalContent'; diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts new file mode 100644 index 000000000..7be2f2141 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.style.ts @@ -0,0 +1,27 @@ +import {css} from '@emotion/react'; + +export const bottomSheetStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1rem', +}); + +export const bottomSheetHeaderStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignContent: 'center', + + width: '100%', + padding: '0 0.5rem', +}); + +export const inputGroupStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '11rem', +}); diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx new file mode 100644 index 000000000..04242fad1 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/DeleteMemberActionModal.tsx @@ -0,0 +1,88 @@ +import type {MemberAction, MemberType} from 'types/serviceType'; + +import {BottomSheet, Flex, Input, Text, IconButton, FixedButton, Icon} from 'haengdong-design'; + +import useDeleteMemberAction from '@hooks/useDeleteMemberAction/useDeleteMemberAction'; +import {useToast} from '@hooks/useToast/useToast'; + +import {bottomSheetHeaderStyle, bottomSheetStyle, inputGroupStyle} from './DeleteMemberActionModal.style'; + +type DeleteMemberActionModalProps = { + memberActionType: MemberType; + memberActionList: MemberAction[]; + isBottomSheetOpened: boolean; + setIsBottomSheetOpened: React.Dispatch>; +}; + +const DeleteMemberActionModal = ({ + memberActionType, + memberActionList, + isBottomSheetOpened, + setIsBottomSheetOpened, +}: DeleteMemberActionModalProps) => { + const {showToast} = useToast(); + + const showToastAlreadyExistMemberAction = () => { + showToast({ + isClickToClose: true, + showingTime: 3000, + message: '이미 삭제된 인원입니다.', + type: 'error', + bottom: '160px', + }); + }; + + const showToastExistSameMemberFromAfterStep = (name: string) => { + showToast({ + isClickToClose: true, + showingTime: 3000, + message: `이후의 ${name}가 사라져요`, + type: 'error', + position: 'top', + top: '30px', + style: { + zIndex: 9000, + }, + }); + }; + + const {aliveActionList, deleteMemberActionList, addDeleteMemberAction} = useDeleteMemberAction({ + memberActionList, + setIsBottomSheetOpened, + showToastAlreadyExistMemberAction, + showToastExistSameMemberFromAfterStep, + }); + + return ( + setIsBottomSheetOpened(false)}> +
+
+ {memberActionType === 'IN' ? '들어온' : '나간'} 인원 수정하기 + {`${aliveActionList.length}명`} +
+
    + {aliveActionList.map(member => ( +
  • + +
    + +
    + addDeleteMemberAction(member)}> + + +
    +
  • + ))} +
+ +
+
+ ); +}; + +export default DeleteMemberActionModal; diff --git a/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts new file mode 100644 index 000000000..2a6b52b45 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/DeleteMemberActionModal/index.ts @@ -0,0 +1 @@ +export {default as DeleteMemberActionModal} from './DeleteMemberActionModal'; diff --git a/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx new file mode 100644 index 000000000..5f7d4501e --- /dev/null +++ b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeleteBillActionModal.tsx @@ -0,0 +1,149 @@ +import type {BillAction} from 'types/serviceType'; + +import {BottomSheet, EditableItem, FixedButton, Flex, Text} from 'haengdong-design'; + +import validatePurchase from '@utils/validate/validatePurchase'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import useMemberReportListInAction from '@hooks/useMemberReportListInAction/useMemberReportListInAction'; +import useMemberReportInput from '@hooks/useMemberReportListInAction/useMemberReportInput'; + +import usePutAndDeleteBillAction from '@hooks/usePutAndDeleteBillAction'; + +import {bottomSheetHeaderStyle, bottomSheetStyle, inputContainerStyle} from './PutAndDeltetBillActionModal.style'; + +type PutAndDeleteBillActionModalProps = { + billAction: BillAction; + isBottomSheetOpened: boolean; + setIsBottomSheetOpened: React.Dispatch>; +}; + +const PutAndDeleteBillActionModal = ({ + billAction, + isBottomSheetOpened, + setIsBottomSheetOpened, +}: PutAndDeleteBillActionModalProps) => { + const { + inputPair, + handleInputChange, + // handleOnBlur, + // errorMessage, + // errorInfo, + canSubmit, + onDelete, + onSubmit: putBillAction, + } = usePutAndDeleteBillAction( + {title: billAction.name, price: String(billAction.price), index: 0}, + validatePurchase, + () => setIsBottomSheetOpened(false), + ); + + const { + memberReportListInAction, + addAdjustedMember, + onSubmit: putMemberReportListInAction, + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + isExistAdjustedPrice, + } = useMemberReportListInAction(billAction.actionId, Number(inputPair.price), () => setIsBottomSheetOpened(false)); + const { + inputList, + onChange, + canEditList, + canSubmit: isChangedMemberReportInput, + } = useMemberReportInput({ + data: memberReportListInAction, + addAdjustedMember, + totalPrice: Number(inputPair.price), + getIsSamePriceStateAndServerState, + getOnlyOneNotAdjustedRemainMemberIndex, + }); + + const {data: stepListData = []} = useRequestGetStepList(); + + const actionMemberList = stepListData.filter(({actions}) => + actions.find(({actionId}) => actionId === billAction.actionId), + )[0].members; + + return ( + setIsBottomSheetOpened(false)}> +
{ + event.preventDefault(); + + if (canSubmit) await putBillAction(event, inputPair, billAction.actionId); + if (isChangedMemberReportInput) putMemberReportListInAction(); + }} + > +

+ 지출 내역 수정하기 +

+
+ + ) => handleInputChange('title', event)} + /> + + ) => handleInputChange('price', event)} + isFixed={isExistAdjustedPrice()} + /> + + + + + + + {inputList.map(({name, price, isFixed}, index) => ( + + + + onChange(event, index)} + isFixed={isFixed} + textSize="smallBody" + value={price} + placeholder="0" + type="number" + readOnly={!canEditList[index]} + style={{textAlign: 'right'}} + > + + + + ))} + + +
+ onDelete(billAction.actionId)} + > + 수정 완료 + +
+
+ ); +}; + +export default PutAndDeleteBillActionModal; diff --git a/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts new file mode 100644 index 000000000..f58f43425 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/PutAndDeltetBillActionModal.style.ts @@ -0,0 +1,28 @@ +import {css} from '@emotion/react'; + +export const bottomSheetStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1rem', +}); + +export const bottomSheetHeaderStyle = css({ + display: 'flex', + justifyContent: 'space-between', + alignContent: 'center', + + width: '100%', + padding: '0 0.5rem', +}); + +export const inputContainerStyle = css({ + display: 'flex', + height: '100%', + flexDirection: 'column', + gap: '1.5rem', + overflow: 'auto', + paddingBottom: '14rem', +}); diff --git a/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts new file mode 100644 index 000000000..c7cbcfcb6 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/PutAndDeleteBillActionModal/index.ts @@ -0,0 +1 @@ +export {default as PutAndDeleteBillActionModal} from './PutAndDeleteBillActionModal'; diff --git a/client/src/components/Modal/SetActionModal/SetActionListModal.style.ts b/client/src/components/Modal/SetActionModal/SetActionListModal.style.ts new file mode 100644 index 000000000..ca6703309 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/SetActionListModal.style.ts @@ -0,0 +1,20 @@ +import {css} from '@emotion/react'; + +export const container = css({ + display: 'flex', + flexDirection: 'column', + width: '100%', + height: '100%', + padding: '0 1.5rem', + gap: '1.5rem', +}); + +export const switchContainer = css({ + display: 'flex', + width: '100%', + justifyContent: 'space-between', +}); + +const setActionListModalStyle = {container, switchContainer}; + +export default setActionListModalStyle; diff --git a/client/src/components/Modal/SetActionModal/SetActionListModal.tsx b/client/src/components/Modal/SetActionModal/SetActionListModal.tsx new file mode 100644 index 000000000..862bd91e3 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/SetActionListModal.tsx @@ -0,0 +1,42 @@ +import type {InOutType} from 'types/serviceType'; + +import {useState} from 'react'; +import {BottomSheet, Switch, Text} from 'haengdong-design'; + +import {AddMemberActionListModalContent} from './AddMemberActionListModalContent'; +import style from './SetActionListModal.style'; + +export type ActionType = '지출' | '인원'; + +interface SetActionModalContentProps { + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +} + +const SetActionListModal = ({isOpenBottomSheet, setIsOpenBottomSheet}: SetActionModalContentProps) => { + const [inOutAction, setInOutAction] = useState('탈주'); + + const handleParticipantTypeChange = (value: string) => { + setInOutAction(value as InOutType); + }; + + return ( + setIsOpenBottomSheet(false)}> +
+
+ + 인원 변동 + + +
+ + +
+
+ ); +}; + +export default SetActionListModal; diff --git a/client/src/components/Modal/SetActionModal/index.ts b/client/src/components/Modal/SetActionModal/index.ts new file mode 100644 index 000000000..f689cb596 --- /dev/null +++ b/client/src/components/Modal/SetActionModal/index.ts @@ -0,0 +1 @@ +export {default as SetActionListModal} from './SetActionListModal'; diff --git a/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts new file mode 100644 index 000000000..f54166c08 --- /dev/null +++ b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.style.ts @@ -0,0 +1,36 @@ +import {css} from '@emotion/react'; + +export const allMemberListModalStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + width: '100%', + height: '100%', + }); + +export const allMemberListModalTitleStyle = () => + css({ + display: 'flex', + justifyContent: 'space-between', + width: '100%', + padding: '0 1.5rem', + }); + +export const allMemberListModalLabelGroupInputStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + padding: '0 1rem', + paddingBottom: '10rem', + + overflow: 'auto', + }); + +export const InputAndDeleteButtonContainer = () => + css({ + display: 'flex', + alignItems: 'center', + width: '100%', + gap: '1rem', + }); diff --git a/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx new file mode 100644 index 000000000..58e86b917 --- /dev/null +++ b/client/src/components/Modal/SetAllMemberListModal/SetAllMemberListModal.tsx @@ -0,0 +1,80 @@ +import {BottomSheet, Text, LabelGroupInput, FixedButton, IconButton, Icon} from 'haengdong-design'; + +import validateMemberName from '@utils/validate/validateMemberName'; + +import useSetAllMemberList from '@hooks/useSetAllMemberList'; + +import { + allMemberListModalLabelGroupInputStyle, + allMemberListModalStyle, + allMemberListModalTitleStyle, + InputAndDeleteButtonContainer, +} from './SetAllMemberListModal.style'; + +interface SetAllMemberListModalProps { + isOpenBottomSheet: boolean; + allMemberList: string[]; + setIsOpenBottomSheet: React.Dispatch>; + setIsOpenAllMemberListButton: React.Dispatch>; +} + +const SetAllMemberListModal = ({ + isOpenBottomSheet, + allMemberList, + setIsOpenBottomSheet, + setIsOpenAllMemberListButton, +}: SetAllMemberListModalProps) => { + const handleCloseAllMemberListModal = () => { + setIsOpenAllMemberListButton(prev => !prev); + setIsOpenBottomSheet(false); + }; + + const { + editedAllMemberList, + canSubmit, + errorMessage, + errorIndexList, + handleNameChange, + handleClickDeleteButton, + handlePutAllMemberList, + } = useSetAllMemberList({ + validateFunc: validateMemberName, + allMemberList, + handleCloseAllMemberListModal, + }); + + return ( + +
+
+ 전체 참여자 수정하기 + + 총 {allMemberList.length}명 + +
+
+ + {editedAllMemberList.map((member, index) => ( +
+
+ handleNameChange(index, e)} + /> +
+ handleClickDeleteButton(index)}> + + +
+ ))} +
+
+ +
+
+ ); +}; + +export default SetAllMemberListModal; diff --git a/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts new file mode 100644 index 000000000..ed835682c --- /dev/null +++ b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.style.ts @@ -0,0 +1,20 @@ +import {css} from '@emotion/react'; + +export const setInitialMemberListModalStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1.5rem', + width: '100%', + height: '100%', + padding: '0 1.5rem', + }); + +export const setInitialMemberListModalInputGroupStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + overflow: 'auto', + paddingBottom: '11rem', + }); diff --git a/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx new file mode 100644 index 000000000..f73f2616d --- /dev/null +++ b/client/src/components/Modal/SetInitialMemberListModal/SetInitialMemberListModal.tsx @@ -0,0 +1,66 @@ +import {Text, BottomSheet, FixedButton, LabelGroupInput} from 'haengdong-design'; + +import validateMemberName from '@utils/validate/validateMemberName'; +import useRequestPostMemberList from '@hooks/queries/useRequestPostMemberList'; + +import useDynamicInput from '@hooks/useDynamicInput'; + +import { + setInitialMemberListModalInputGroupStyle, + setInitialMemberListModalStyle, +} from './SetInitialMemberListModal.style'; + +interface SetInitialMemberListProps { + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +} + +const SetInitialMemberListModal = ({isOpenBottomSheet, setIsOpenBottomSheet}: SetInitialMemberListProps) => { + const { + inputList, + inputRefList, + handleInputChange, + deleteEmptyInputElementOnBlur, + getFilledInputList, + errorMessage, + canSubmit, + errorIndexList, + focusNextInputOnEnter, + } = useDynamicInput(validateMemberName); + const {mutate: postMemberList} = useRequestPostMemberList(); + + const handleSubmit = () => { + postMemberList({memberNameList: getFilledInputList().map(({value}) => value), type: 'IN'}); + setIsOpenBottomSheet(false); + }; + + return ( + setIsOpenBottomSheet(false)}> +
+ 시작 인원 추가하기 +
+ + {inputList.map(({value, index}) => ( + (inputRefList.current[index] = el)} + onChange={e => handleInputChange(index, e)} + onBlur={() => deleteEmptyInputElementOnBlur()} + onKeyDown={e => focusNextInputOnEnter(e, index)} + autoFocus={inputList.length === 1 && index === 0} + /> + ))} + +
+
+ +
+ ); +}; + +export default SetInitialMemberListModal; diff --git a/client/src/components/Modal/SetInitialMemberListModal/index.ts b/client/src/components/Modal/SetInitialMemberListModal/index.ts new file mode 100644 index 000000000..18098e4f6 --- /dev/null +++ b/client/src/components/Modal/SetInitialMemberListModal/index.ts @@ -0,0 +1 @@ +export {default as SetInitialMemberListModal} from './SetInitialMemberListModal'; diff --git a/client/src/components/Modal/index.ts b/client/src/components/Modal/index.ts new file mode 100644 index 000000000..180063b03 --- /dev/null +++ b/client/src/components/Modal/index.ts @@ -0,0 +1,4 @@ +export {default as SetActionListModal} from './SetActionModal/SetActionListModal'; +export {default as SetInitialMemberListModal} from './SetInitialMemberListModal/SetInitialMemberListModal'; +export {default as SetAllMemberListModal} from './SetAllMemberListModal/SetAllMemberListModal'; +export {default as ModalBasedOnMemberCount} from './ModalBasedOnMemberCount/ModalBasedOnMemberCount'; diff --git a/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx b/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx new file mode 100644 index 000000000..aeec24c3a --- /dev/null +++ b/client/src/components/QueryClientBoundary/QueryClientBoundary.tsx @@ -0,0 +1,24 @@ +import {MutationCache, QueryCache, QueryClient, QueryClientProvider} from '@tanstack/react-query'; + +import {useAppErrorStore} from '@store/appErrorStore'; + +const QueryClientBoundary = ({children}: React.PropsWithChildren) => { + const {updateAppError} = useAppErrorStore(); + + const queryClient = new QueryClient({ + queryCache: new QueryCache({ + onError: (error: Error) => { + updateAppError(error); + }, + }), + mutationCache: new MutationCache({ + onError: (error: Error) => { + updateAppError(error); + }, + }), + }); + + return {children}; +}; + +export default QueryClientBoundary; diff --git a/client/src/components/StepList/BillStepItem.tsx b/client/src/components/StepList/BillStepItem.tsx new file mode 100644 index 000000000..7fed9ef5c --- /dev/null +++ b/client/src/components/StepList/BillStepItem.tsx @@ -0,0 +1,138 @@ +import {DragHandleItem, DragHandleItemContainer, EditableItem, Flex, Text} from 'haengdong-design'; +import {Fragment, useState} from 'react'; +import {useOutletContext} from 'react-router-dom'; + +import {BillStep, MemberReport} from 'types/serviceType'; +import {PutAndDeleteBillActionModal} from '@components/Modal/SetActionModal/PutAndDeleteBillActionModal'; +import {MemberListInBillStep} from '@components/Modal/MemberListInBillStep'; +import {EventPageContextProps} from '@pages/EventPage/EventPageLayout'; +import ExpenseDetailModal from '@components/Modal/ExpenseDetailModal/ExpenseDetailModal'; + +import useSetBillInput from '@hooks/useSetBillInput'; + +interface BillStepItemProps { + step: BillStep; + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; + isAddEditableItem: boolean; + setIsAddEditableItem: React.Dispatch>; + isLastBillItem: boolean; + index: number; +} + +const BillStepItem: React.FC = ({ + step, + isOpenBottomSheet, + setIsOpenBottomSheet, + isAddEditableItem, + setIsAddEditableItem, + isLastBillItem, + index, +}) => { + const {isAdmin} = useOutletContext(); + const {handleBlurBillRequest, handleChangeBillInput, billInput} = useSetBillInput({setIsAddEditableItem}); + + const [clickedIndex, setClickedIndex] = useState(-1); + const [isOpenMemberListInBillStep, setIsOpenMemberListInBillStep] = useState(false); + + const totalPrice = step.actions && step.type === 'BILL' ? step.actions.reduce((acc, cur) => acc + cur.price, 0) : 0; + + const handleDragHandleItemClick = (index: number) => { + setClickedIndex(index); + setIsOpenBottomSheet(true); + }; + + const memberList: MemberReport[] = step.members.map(member => ({ + name: member, + price: totalPrice / step.members.length, + })); + + const handleTopRightTextClick = () => { + setIsOpenMemberListInBillStep(true); + }; + + return ( + <> + + {step.actions && + step.type === 'BILL' && + step.actions.map((action, index) => ( + + handleDragHandleItemClick(index)} + isFixed={action.isFixed} + /> + + {isOpenBottomSheet && clickedIndex === index && isAdmin && ( + + )} + {isOpenBottomSheet && clickedIndex === index && !isAdmin && ( + + )} + + ))} + + {isAddEditableItem && isLastBillItem && ( + { + if (e.key === 'Enter') { + handleBlurBillRequest(); + } + }} + > + handleChangeBillInput('title', e)} + autoFocus + > + + handleChangeBillInput('price', e)} + style={{textAlign: 'right'}} + > + + + + )} + + + + ); +}; + +export default BillStepItem; diff --git a/client/src/components/StepList/MemberStepItem.tsx b/client/src/components/StepList/MemberStepItem.tsx new file mode 100644 index 000000000..ed3f5bfe7 --- /dev/null +++ b/client/src/components/StepList/MemberStepItem.tsx @@ -0,0 +1,38 @@ +import type {MemberStep} from 'types/serviceType'; + +import {DragHandleItem} from 'haengdong-design'; +import {useOutletContext} from 'react-router-dom'; + +import {DeleteMemberActionModal} from '@components/Modal/SetActionModal/DeleteMemberActionModal'; +import {EventPageContextProps} from '@pages/EventPage/EventPageLayout'; + +interface MemberStepItemProps { + step: MemberStep; + isOpenBottomSheet: boolean; + setIsOpenBottomSheet: React.Dispatch>; +} + +const MemberStepItem: React.FC = ({step, isOpenBottomSheet, setIsOpenBottomSheet}) => { + const {isAdmin} = useOutletContext(); + + return ( + <> + name).join(', ')} ${step.type === 'IN' ? '들어옴' : '나감'}`} + onClick={() => setIsOpenBottomSheet(prev => !prev)} + /> + {isOpenBottomSheet && isAdmin && ( + + )} + + ); +}; + +export default MemberStepItem; diff --git a/client/src/components/StepList/Step.tsx b/client/src/components/StepList/Step.tsx new file mode 100644 index 000000000..f6c89475b --- /dev/null +++ b/client/src/components/StepList/Step.tsx @@ -0,0 +1,51 @@ +import type {BillStep, MemberStep} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import BillStepItem from './BillStepItem'; +import MemberStepItem from './MemberStepItem'; + +interface StepProps { + step: BillStep | MemberStep; + isAddEditableItem: boolean; + lastBillItemIndex: number; + lastItemIndex: number; + index: number; + setIsAddEditableItem: React.Dispatch>; +} + +const Step = ({step, isAddEditableItem, lastBillItemIndex, lastItemIndex, setIsAddEditableItem, index}: StepProps) => { + const [isOpenBottomSheet, setIsOpenBottomSheet] = useState(false); + const [isLastBillItem, setIsLastBillItem] = useState(false); + + useEffect(() => { + if (index === lastBillItemIndex && lastBillItemIndex === lastItemIndex) { + // index를 사용하여 마지막 BillStep인지 확인 + setIsLastBillItem(true); + } else { + setIsLastBillItem(false); + } + }, [index, lastBillItemIndex]); + + if (step.actions && step.type === 'BILL') { + return ( + + ); + } else if (step.actions && (step.type === 'IN' || step.type === 'OUT')) { + return ( + + ); + } else { + return <>; + } +}; + +export default Step; diff --git a/client/src/components/StepList/StepList.tsx b/client/src/components/StepList/StepList.tsx new file mode 100644 index 000000000..d6a507247 --- /dev/null +++ b/client/src/components/StepList/StepList.tsx @@ -0,0 +1,76 @@ +import {Flex} from 'haengdong-design'; +import {useEffect, useMemo, useState} from 'react'; + +import {BillStep, MemberStep} from 'types/serviceType'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; + +import Step from './Step'; + +interface StepListProps { + isAddEditableItem?: boolean; + setIsAddEditableItem?: React.Dispatch>; +} + +const StepList = ({isAddEditableItem = false, setIsAddEditableItem = () => {}}: StepListProps) => { + const {data: stepListData} = useRequestGetStepList(); + const [stepList, setStepList] = useState<(MemberStep | BillStep)[]>([]); + const existIndexInStepList = stepList.map((step, index) => ({...step, index})); + const [hasAddedItem, setHasAddedItem] = useState(false); + const nextStepName = stepList.length > 0 ? String(stepList[stepList.length - 1].stepName).match(/.*(?=차)/) : ''; + + useEffect(() => { + if (stepListData) { + setStepList(stepListData); + } + }, [stepListData]); + + const lastBillItemIndex = useMemo(() => { + const billSteps = existIndexInStepList.filter(step => step.type === 'BILL'); + + // billSteps 배열이 비어 있지 않으면 마지막 항목의 index를 반환, 그렇지 않으면 -1을 반환 + return billSteps.length > 0 ? billSteps.slice(-1)[0].index : -1; + }, [stepList]); + + const lastItemIndex = useMemo(() => { + return existIndexInStepList.length > 0 ? existIndexInStepList.slice(-1)[0].index : -1; + }, [existIndexInStepList]); + + useEffect(() => { + if (hasAddedItem) { + setHasAddedItem(false); + + setStepList(prev => [...prev.filter(({actions}) => actions.length !== 0)]); + } + + if (isAddEditableItem && lastBillItemIndex !== lastItemIndex && !hasAddedItem) { + setStepList(prev => [ + ...prev, + { + type: 'BILL', + stepName: `${Number(nextStepName) + 1}차`, + members: [], + actions: [], + }, + ]); + setHasAddedItem(prev => !prev); + } + }, [isAddEditableItem]); + + return ( + + {stepList.map((step, index) => ( + + ))} + + ); +}; + +export default StepList; diff --git a/client/src/components/Toast/Toast.style.ts b/client/src/components/Toast/Toast.style.ts new file mode 100644 index 000000000..a0b5c7cd4 --- /dev/null +++ b/client/src/components/Toast/Toast.style.ts @@ -0,0 +1,65 @@ +import {css, keyframes} from '@emotion/react'; + +import {ToastPosition} from './Toast.type'; + +type ToastMarginStyle = { + position?: ToastPosition; + bottom?: string; + top?: string; +}; + +// 애니메이션 키프레임 정의 +const fadeInWithTransformY = keyframes` + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +`; + +const fadeOutWithTransformY = keyframes` + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(20px); + } +`; + +export const toastMarginStyle = ({position, bottom, top}: ToastMarginStyle) => + css({ + position: 'absolute', + bottom: position === 'bottom' ? `${bottom}` : 'auto', + top: position === 'top' ? `${top}` : 'auto', + left: '50%', + transform: 'translate(-50%)', + + width: '100%', + maxWidth: '48rem', + paddingInline: '1rem', + }); + +export const toastStyle = (isVisible: boolean) => + css({ + width: '100%', + padding: '0.625rem 1rem', + + backgroundColor: 'gray', + boxShadow: '0 0.5rem 0.75rem rgba(0, 0, 0, 0.16);', + + borderRadius: '1.25rem', + + // 애니메이션 추가 + animation: `${isVisible ? fadeInWithTransformY : fadeOutWithTransformY} 0.5s forwards`, + }); + +export const textStyle = css({ + width: '100%', + color: 'white', + whiteSpace: 'pre-line', +}); diff --git a/client/src/components/Toast/Toast.tsx b/client/src/components/Toast/Toast.tsx new file mode 100644 index 000000000..5bf44d6fb --- /dev/null +++ b/client/src/components/Toast/Toast.tsx @@ -0,0 +1,75 @@ +import {createPortal} from 'react-dom'; +import {useState, useEffect} from 'react'; +import {Button, Flex, Icon, Text} from 'haengdong-design'; + +import {toastStyle, textStyle, toastMarginStyle} from './Toast.style'; +import {ToastProps, ToastType} from './Toast.type'; + +const renderIcon = (type: ToastType) => { + if (type === 'none') return null; + + return ; +}; + +const ANIMATION_TIME = 500; + +const Toast = ({ + type = 'confirm', + top = '0px', + bottom = '0px', + isClickToClose = true, + position = 'bottom', + showingTime = 3000, + message, + onUndo, + onClose, + ...htmlProps +}: ToastProps) => { + const [isVisible, setIsVisible] = useState(true); + const styleProps = {position, top, bottom}; + + useEffect(() => { + const timer = setTimeout(() => { + setIsVisible(false); + setTimeout(() => { + if (onClose) onClose(); + }, ANIMATION_TIME); // fadeOut 애니메이션 시간과 동일하게 설정 + }, showingTime - ANIMATION_TIME); // 토스트가 내려가는 시간 확보 + + return () => { + clearTimeout(timer); + }; + }, [onClose]); + + const handleClickToClose = () => { + if (!isClickToClose || !onClose) return; + + setIsVisible(false); + setTimeout(() => { + onClose(); + }, ANIMATION_TIME); // fadeOut 애니메이션 시간과 동일하게 설정 + }; + + return createPortal( +
+
+ + + {renderIcon(type)} + + {message} + + + {onUndo && ( + + )} + +
+
, + document.body, + ); +}; + +export default Toast; diff --git a/client/src/components/Toast/Toast.type.ts b/client/src/components/Toast/Toast.type.ts new file mode 100644 index 000000000..20b92c0db --- /dev/null +++ b/client/src/components/Toast/Toast.type.ts @@ -0,0 +1,22 @@ +export type ToastPosition = 'bottom' | 'top'; +export type ToastType = 'error' | 'confirm' | 'none'; + +export interface ToastStyleProps { + bottom?: string; + top?: string; +} + +export interface ToastOptionProps { + position?: ToastPosition; + type?: ToastType; + onUndo?: () => void; + isClickToClose?: boolean; + onClose?: () => void; + showingTime?: number; +} + +export interface ToastRequiredProps { + message: string; +} + +export type ToastProps = React.ComponentProps<'div'> & ToastStyleProps & ToastOptionProps & ToastRequiredProps; diff --git a/client/src/constants/errorMessage.ts b/client/src/constants/errorMessage.ts new file mode 100644 index 000000000..42703bdf0 --- /dev/null +++ b/client/src/constants/errorMessage.ts @@ -0,0 +1,49 @@ +type ErrorMessage = Record; + +export const SERVER_ERROR_MESSAGES: ErrorMessage = { + EVENT_NOT_FOUND: '존재하지 않는 행사입니다.', + EVENT_NAME_LENGTH_INVALID: '행사 이름은 2자 이상 30자 이하만 입력 가능합니다.', + EVENT_NAME_CONSECUTIVE_SPACES: '행사 이름에는 공백 문자가 연속될 수 없습니다.', + EVENT_PASSWORD_FORMAT_INVALID: '비밀번호는 4자리 숫자만 가능합니다.', + + ACTION_NOT_FOUND: '존재하지 않는 액션입니다.', + + MEMBER_NAME_LENGTH_INVALID: '멤버 이름은 1자 이상 4자 이하만 입력 가능합니다.', + MEMBER_NAME_DUPLICATE: '중복된 행사 참여 인원 이름이 존재합니다.', + MEMBER_NOT_EXIST: '현재 참여하고 있지 않은 인원이 존재합니다.', + MEMBER_ALREADY_EXIST: '현재 참여하고 있는 인원이 존재합니다.', + + MEMBER_ACTION_NOT_FOUND: '존재하지 않는 멤버 액션입니다.', + MEMBER_ACTION_STATUS_INVALID: '유효하지 않은 멤버 액션 상태입니다.', + + BILL_ACTION_NOT_FOUND: '존재하지 않는 지출 액션입니다.', + BILL_ACTION_TITLE_INVALID: '앞뒤 공백을 제거한 지출 내역 제목은 %d자 ~ %d자여야 합니다.', + BILL_ACTION_PRICE_INVALID: '지출 금액은 10,000,000 이하의 자연수여야 합니다.', + + REQUEST_EMPTY: '입력 값은 공백일 수 없습니다.', + MESSAGE_NOT_READABLE: '읽을 수 없는 요청입니다.', + NO_RESOURCE_REQUEST: '존재하지 않는 자원입니다.', + REQUEST_METHOD_NOT_SUPPORTED: '지원하지 않는 요청 메서드입니다.', + + INTERNAL_SERVER_ERROR: '서버 내부에 에러가 발생했습니다.', + + PASSWORD_INVALID: '비밀번호가 일치하지 않습니다.', + TOKEN_NOT_FOUND: '토큰이 존재하지 않습니다.', + TOKEN_EXPIRED: '만료된 토큰입니다.', + TOKEN_INVALID: '유효하지 않은 토큰입니다.', + FORBIDDEN: '접근할 수 없는 행사입니다.', + + UNHANDLED: '알 수 없는 에러입니다.', +}; + +export const ERROR_MESSAGE = { + eventName: '행사 이름은 30자 이하만 가능해요', + eventPasswordType: '비밀번호는 숫자만 입력이 가능해요', + memberName: '참여자 이름은 4자 이하의 한글, 영어만 가능해요', + purchasePrice: '10,000,000원 이하의 숫자만 입력이 가능해요', + purchaseTitle: '지출 이름은 30자 이하의 한글, 영어, 숫자만 가능해요', + preventEmpty: '값은 비어있을 수 없어요', + invalidInput: '올바르지 않은 입력이에요.', +}; + +export const UNKNOWN_ERROR = 'UNKNOWN_ERROR'; diff --git a/client/src/constants/password.ts b/client/src/constants/password.ts new file mode 100644 index 000000000..cfb26b39c --- /dev/null +++ b/client/src/constants/password.ts @@ -0,0 +1 @@ +export const PASSWORD_LENGTH = 4; diff --git a/client/src/constants/queryKeys.ts b/client/src/constants/queryKeys.ts new file mode 100644 index 000000000..17f3f4586 --- /dev/null +++ b/client/src/constants/queryKeys.ts @@ -0,0 +1,10 @@ +const QUERY_KEYS = { + stepList: 'stepList', + eventName: 'eventName', + allMemberList: 'allMemberList', + currentInMember: 'currentInMember', + memberReport: 'memberReport', + memberReportInAction: 'memberReportInAction', +}; + +export default QUERY_KEYS; diff --git a/client/src/constants/regExp.ts b/client/src/constants/regExp.ts new file mode 100644 index 000000000..4d910ac99 --- /dev/null +++ b/client/src/constants/regExp.ts @@ -0,0 +1,8 @@ +const REGEXP = { + eventPassword: /^[0-9]*$/, + memberName: /^[ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z\s]*$/, + purchaseTitle: /^[ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z0-9\s]*$/, + eventUrl: /\/event\/([a-zA-Z0-9-]+)\//, +}; + +export default REGEXP; diff --git a/client/src/constants/routerUrls.ts b/client/src/constants/routerUrls.ts new file mode 100644 index 000000000..6a3634c3b --- /dev/null +++ b/client/src/constants/routerUrls.ts @@ -0,0 +1,10 @@ +export const ROUTER_URLS = { + main: '/', + eventCreateName: '/event/create/name', + eventCreatePassword: '/event/create/password', + eventCreateComplete: '/event/create/complete', + event: '/event', // TODO: (@weadie) baseurl을 어떻게 관리할 것인가? + eventLogin: '/event/:eventId/login', + eventManage: '/event/:eventId/admin', + home: '/event/:eventId/home', +}; diff --git a/client/src/constants/rule.ts b/client/src/constants/rule.ts new file mode 100644 index 000000000..4b78031b9 --- /dev/null +++ b/client/src/constants/rule.ts @@ -0,0 +1,8 @@ +const RULE = { + maxEventNameLength: 30, + maxEventPasswordLength: 4, + maxMemberNameLength: 4, + maxPrice: 10000000, +}; + +export default RULE; diff --git a/client/src/errors/FetchError.ts b/client/src/errors/FetchError.ts new file mode 100644 index 000000000..9123a80b5 --- /dev/null +++ b/client/src/errors/FetchError.ts @@ -0,0 +1,23 @@ +import {FetchErrorType} from '../types/fetchErrorType'; + +class FetchError extends Error { + requestBody; + status; + endpoint; + errorInfo; + method; + + constructor({requestBody, status, endpoint, errorInfo, method, name, message}: FetchErrorType) { + super(errorInfo.errorCode); + + this.requestBody = requestBody; + this.status = status; + this.endpoint = endpoint; + this.errorInfo = errorInfo; + this.method = method; + this.name = name; + this.message = message; + } +} + +export default FetchError; diff --git a/client/src/global.d.ts b/client/src/global.d.ts new file mode 100644 index 000000000..dbf6320af --- /dev/null +++ b/client/src/global.d.ts @@ -0,0 +1,11 @@ +declare module '*.svg'; + +declare namespace NodeJS { + interface ProcessEnv { + readonly NODE_ENV: 'development' | 'production' | 'test'; + + // env keys + readonly API_BASE_URL: string; + readonly AMPLITUDE_KEY: string; + } +} diff --git a/client/src/hooks/queries/useRequestDeleteAllMemberList.ts b/client/src/hooks/queries/useRequestDeleteAllMemberList.ts new file mode 100644 index 000000000..da6fc4223 --- /dev/null +++ b/client/src/hooks/queries/useRequestDeleteAllMemberList.ts @@ -0,0 +1,28 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestDeleteAllMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface DeleteAllMemberListMutationProps { + memberName: string; +} + +const useRequestDeleteAllMemberList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({memberName}: DeleteAllMemberListMutationProps) => requestDeleteAllMemberList({eventId, memberName}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + queryClient.removeQueries({queryKey: [QUERY_KEYS.memberReportInAction]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestDeleteAllMemberList; diff --git a/client/src/hooks/queries/useRequestDeleteBillAction.ts b/client/src/hooks/queries/useRequestDeleteBillAction.ts new file mode 100644 index 000000000..28be9dfd1 --- /dev/null +++ b/client/src/hooks/queries/useRequestDeleteBillAction.ts @@ -0,0 +1,26 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestDeleteBillAction} from '@apis/request/bill'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface DeleteBillActionMutationProps { + actionId: number; +} + +const useRequestDeleteBillAction = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({actionId}: DeleteBillActionMutationProps) => requestDeleteBillAction({eventId, actionId}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestDeleteBillAction; diff --git a/client/src/hooks/queries/useRequestDeleteMemberAction.ts b/client/src/hooks/queries/useRequestDeleteMemberAction.ts new file mode 100644 index 000000000..08e69ac1f --- /dev/null +++ b/client/src/hooks/queries/useRequestDeleteMemberAction.ts @@ -0,0 +1,28 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestDeleteMemberAction} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface DeleteMemberActionMutationProps { + actionId: number; +} + +const useRequestDeleteMemberAction = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({actionId}: DeleteMemberActionMutationProps) => requestDeleteMemberAction({eventId, actionId}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReportInAction]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + }, + }); +}; + +export default useRequestDeleteMemberAction; diff --git a/client/src/hooks/queries/useRequestGetAllMemberList.ts b/client/src/hooks/queries/useRequestGetAllMemberList.ts new file mode 100644 index 000000000..531285fd6 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetAllMemberList.ts @@ -0,0 +1,18 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetAllMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetAllMemberList = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.allMemberList], + queryFn: () => requestGetAllMemberList({eventId}), + }); +}; + +export default useRequestGetAllMemberList; diff --git a/client/src/hooks/queries/useRequestGetCurrentInMemberList.ts b/client/src/hooks/queries/useRequestGetCurrentInMemberList.ts new file mode 100644 index 000000000..31dc058c2 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetCurrentInMemberList.ts @@ -0,0 +1,18 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetCurrentInMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetCurrentInMemberList = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.currentInMember], + queryFn: () => requestGetCurrentInMemberList({eventId}), + }); +}; + +export default useRequestGetCurrentInMemberList; diff --git a/client/src/hooks/queries/useRequestGetEventName.ts b/client/src/hooks/queries/useRequestGetEventName.ts new file mode 100644 index 000000000..6ddb21858 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetEventName.ts @@ -0,0 +1,18 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetEventName} from '@apis/request/event'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetEventName = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.eventName], + queryFn: () => requestGetEventName({eventId}), + }); +}; + +export default useRequestGetEventName; diff --git a/client/src/hooks/queries/useRequestGetMemberReportList.ts b/client/src/hooks/queries/useRequestGetMemberReportList.ts new file mode 100644 index 000000000..fe3372d35 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetMemberReportList.ts @@ -0,0 +1,17 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetMemberReportList} from '@apis/request/report'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetMemberReportList = () => { + const eventId = getEventIdByUrl(); + + return useQuery({ + queryKey: [QUERY_KEYS.memberReport], + queryFn: () => requestGetMemberReportList({eventId}), + }); +}; +export default useRequestGetMemberReportList; diff --git a/client/src/hooks/queries/useRequestGetMemberReportListInAction.ts b/client/src/hooks/queries/useRequestGetMemberReportListInAction.ts new file mode 100644 index 000000000..85b458228 --- /dev/null +++ b/client/src/hooks/queries/useRequestGetMemberReportListInAction.ts @@ -0,0 +1,24 @@ +import {useQuery} from '@tanstack/react-query'; + +import {requestGetMemberReportListInAction} from '@apis/request/bill'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetMemberReportListInAction = (actionId: number) => { + const eventId = getEventIdByUrl(); + + const {data, ...queryResult} = useQuery({ + queryKey: [QUERY_KEYS.memberReportInAction, actionId], + queryFn: () => requestGetMemberReportListInAction({eventId, actionId}), + select: data => data.members, + }); + + return { + memberReportListInActionFromServer: data ?? [], + queryResult, + }; +}; + +export default useRequestGetMemberReportListInAction; diff --git a/client/src/hooks/queries/useRequestGetStepList.ts b/client/src/hooks/queries/useRequestGetStepList.ts new file mode 100644 index 000000000..7dfc1799c --- /dev/null +++ b/client/src/hooks/queries/useRequestGetStepList.ts @@ -0,0 +1,30 @@ +import {useQuery} from '@tanstack/react-query'; +import {useEffect} from 'react'; + +import {requestGetStepList} from '@apis/request/stepList'; + +import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestGetStepList = () => { + const eventId = getEventIdByUrl(); + const {updateTotalExpenseAmount} = useTotalExpenseAmountStore(); + + const queryResult = useQuery({ + queryKey: [QUERY_KEYS.stepList], + queryFn: () => requestGetStepList({eventId}), + }); + + useEffect(() => { + if (queryResult.isSuccess && queryResult.data) { + updateTotalExpenseAmount(queryResult.data); + } + }, [queryResult.data, queryResult.isSuccess, updateTotalExpenseAmount]); + + return queryResult; +}; + +export default useRequestGetStepList; diff --git a/client/src/hooks/queries/useRequestPostAuthentication.ts b/client/src/hooks/queries/useRequestPostAuthentication.ts new file mode 100644 index 000000000..e533a501b --- /dev/null +++ b/client/src/hooks/queries/useRequestPostAuthentication.ts @@ -0,0 +1,23 @@ +import {useMutation} from '@tanstack/react-query'; +import {useNavigate} from 'react-router-dom'; + +import {requestPostAuthentication} from '@apis/request/auth'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const useRequestPostAuthenticate = () => { + const eventId = getEventIdByUrl(); + const navigate = useNavigate(); + + return useMutation({ + mutationFn: () => requestPostAuthentication({eventId}), + onError: () => { + // 에러가 발생하면 로그인 페이지로 리다이렉트 + navigate(`${ROUTER_URLS.event}/${eventId}/login`); + }, + }); +}; + +export default useRequestPostAuthenticate; diff --git a/client/src/hooks/queries/useRequestPostBillList.ts b/client/src/hooks/queries/useRequestPostBillList.ts new file mode 100644 index 000000000..676da9d85 --- /dev/null +++ b/client/src/hooks/queries/useRequestPostBillList.ts @@ -0,0 +1,27 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestPostBillList} from '@apis/request/bill'; +import {Bill} from 'types/serviceType'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PostBillActionMutationProps { + billList: Bill[]; +} + +const useRequestPostBillList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({billList}: PostBillActionMutationProps) => requestPostBillList({eventId, billList}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPostBillList; diff --git a/client/src/hooks/queries/useRequestPostEvent.ts b/client/src/hooks/queries/useRequestPostEvent.ts new file mode 100644 index 000000000..5327710fc --- /dev/null +++ b/client/src/hooks/queries/useRequestPostEvent.ts @@ -0,0 +1,16 @@ +import {useMutation} from '@tanstack/react-query'; + +import {requestPostNewEvent} from '@apis/request/event'; + +interface PostEventMutationProps { + eventName: string; + password: number; +} + +const usePostEvent = () => { + return useMutation({ + mutationFn: ({eventName, password}: PostEventMutationProps) => requestPostNewEvent({eventName, password}), + }); +}; + +export default usePostEvent; diff --git a/client/src/hooks/queries/useRequestPostLogin.ts b/client/src/hooks/queries/useRequestPostLogin.ts new file mode 100644 index 000000000..21dce1791 --- /dev/null +++ b/client/src/hooks/queries/useRequestPostLogin.ts @@ -0,0 +1,26 @@ +import {useMutation} from '@tanstack/react-query'; +import {useNavigate} from 'react-router-dom'; + +import {requestPostToken} from '@apis/request/auth'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +interface PostLoginMutationProps { + password: string; +} + +const useRequestPostLogin = () => { + const eventId = getEventIdByUrl(); + const navigate = useNavigate(); + + return useMutation({ + mutationFn: ({password}: PostLoginMutationProps) => requestPostToken({eventId, password}), + onSuccess: () => { + navigate(`${ROUTER_URLS.event}/${eventId}/admin`); + }, + }); +}; + +export default useRequestPostLogin; diff --git a/client/src/hooks/queries/useRequestPostMemberList.ts b/client/src/hooks/queries/useRequestPostMemberList.ts new file mode 100644 index 000000000..8ed69db08 --- /dev/null +++ b/client/src/hooks/queries/useRequestPostMemberList.ts @@ -0,0 +1,37 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {MemberType} from 'types/serviceType'; +import {requestPostMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PostMemberListMutationProps { + type: MemberType; + memberNameList: string[]; +} + +const useRequestPostMemberList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({type, memberNameList}: PostMemberListMutationProps) => + requestPostMemberList({eventId, type, memberNameList}), + // TODO: (@todari) : 낙관적 업데이트 적고 있었어용 + // onMutate: async ({type, memberNameList}) => { + // await queryClient.cancelQueries({queryKey: [QUERY_KEYS.stepList]}); + // const previousStepList = queryClient.getQueryData([QUERY_KEYS.stepList]); + // queryClient.setQueryData([QUERY_KEYS.stepList], (prev: (MemberStep | BillStep)[]) => prev && { + // }); + // }, + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPostMemberList; diff --git a/client/src/hooks/queries/useRequestPutAllMemberList.ts b/client/src/hooks/queries/useRequestPutAllMemberList.ts new file mode 100644 index 000000000..4bd746d0c --- /dev/null +++ b/client/src/hooks/queries/useRequestPutAllMemberList.ts @@ -0,0 +1,28 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {MemberChange, requestPutAllMemberList} from '@apis/request/member'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PutAllMemberListMutationProps { + members: MemberChange[]; +} + +const useRequestPutAllMemberList = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({members}: PutAllMemberListMutationProps) => requestPutAllMemberList({eventId, members}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.allMemberList]}); + queryClient.removeQueries({queryKey: [QUERY_KEYS.memberReportInAction]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPutAllMemberList; diff --git a/client/src/hooks/queries/useRequestPutBillAction.ts b/client/src/hooks/queries/useRequestPutBillAction.ts new file mode 100644 index 000000000..a58da8ea4 --- /dev/null +++ b/client/src/hooks/queries/useRequestPutBillAction.ts @@ -0,0 +1,29 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {requestPutBillAction} from '@apis/request/bill'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +interface PutBillActionMutationProps { + actionId: number; + title: string; + price: number; +} + +const useRequestPutBillAction = () => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({actionId, title, price}: PutBillActionMutationProps) => + requestPutBillAction({eventId, actionId, title, price}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + }, + }); +}; + +export default useRequestPutBillAction; diff --git a/client/src/hooks/queries/useRequestPutMemberReportListInAction.ts b/client/src/hooks/queries/useRequestPutMemberReportListInAction.ts new file mode 100644 index 000000000..a87fa44f1 --- /dev/null +++ b/client/src/hooks/queries/useRequestPutMemberReportListInAction.ts @@ -0,0 +1,49 @@ +import {useMutation, useQueryClient} from '@tanstack/react-query'; + +import {MemberReportList, requestPutMemberReportListInAction} from '@apis/request/bill'; +import {MemberReportInAction} from 'types/serviceType'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +import QUERY_KEYS from '@constants/queryKeys'; + +const useRequestPutMemberReportListInAction = (actionId: number) => { + const eventId = getEventIdByUrl(); + const queryClient = useQueryClient(); + + const {mutate, ...mutationProps} = useMutation({ + mutationFn: (members: MemberReportInAction[]) => requestPutMemberReportListInAction({eventId, actionId, members}), + onSuccess: () => { + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.stepList]}); + queryClient.invalidateQueries({queryKey: [QUERY_KEYS.memberReport]}); + queryClient.removeQueries({queryKey: [QUERY_KEYS.memberReportInAction, actionId]}); + }, + onMutate: async (newMembers: MemberReportInAction[]) => { + await queryClient.cancelQueries({queryKey: [QUERY_KEYS.memberReportInAction, actionId]}); + + const previousMembers = queryClient.getQueryData([QUERY_KEYS.memberReportInAction, actionId]); + + queryClient.setQueryData([QUERY_KEYS.memberReportInAction, actionId], (oldData: MemberReportList) => ({ + ...oldData, + members: oldData.members.map((member: MemberReportInAction) => { + const updatedMember = newMembers.find(m => m.name === member.name); + return updatedMember ? {...member, ...updatedMember} : member; + }), + })); + + return {previousMembers}; + }, + onError: (err, newMembers, context) => { + if (context?.previousMembers) { + queryClient.setQueryData([QUERY_KEYS.memberReportInAction, actionId], context.previousMembers); + } + }, + }); + + return { + putMemberReportListInAction: mutate, + mutationProps, + }; +}; + +export default useRequestPutMemberReportListInAction; diff --git a/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx new file mode 100644 index 000000000..38836f677 --- /dev/null +++ b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.test.tsx @@ -0,0 +1,139 @@ +import {renderHook, waitFor} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; +import {act} from 'react'; +import {HDesignProvider} from 'haengdong-design'; + +import {BillStep, MemberAction, MemberStep} from 'types/serviceType'; +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import AppErrorBoundary from '@components/AppErrorBoundary/ErrorCatcher'; +import QueryClientBoundary from '@components/QueryClientBoundary/QueryClientBoundary'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; + +import stepListJson from '@mocks/stepList.json'; +import invalidMemberStepListJson from '@mocks/invalidMemberStepList.json'; + +import useDeleteMemberAction from './useDeleteMemberAction'; + +const stepListMockData = stepListJson as (BillStep | MemberStep)[]; +let memberActionList: MemberAction[] = []; + +// filter로는 type narrowing이 안되어 부득이하게 for 문을 사용했습니다. +for (let i = 0; i < stepListMockData.length; i++) { + const curAction = stepListMockData[i]; + if (curAction.type !== 'BILL') curAction.actions.forEach(action => memberActionList.push(action)); +} + +describe('useDeleteMemberAction', () => { + const initializeProvider = (list: MemberAction[] = memberActionList) => + renderHook( + () => { + return { + stepListResult: useRequestGetStepList(), + deleteMemberActionList: useDeleteMemberAction({ + memberActionList: list, + setIsBottomSheetOpened: () => {}, + showToastAlreadyExistMemberAction: () => {}, + showToastExistSameMemberFromAfterStep: () => {}, + }), + }; + }, + { + wrapper: ({children}) => ( + + + + + {children} + + + + + ), + }, + ); + + it('멤버를 삭제할 멤버 목록에 추가한다.', async () => { + const {result} = initializeProvider(); + + // stepList 값이 채워지길 대기합니다. + await waitFor(() => { + expect(result.current.stepListResult.data).not.toStrictEqual([]); + }); + + act(() => { + const memberAction = { + actionId: 1, + name: '망쵸', + price: null, + sequence: 1, + isFixed: false, + }; + + result.current.deleteMemberActionList.addDeleteMemberAction(memberAction); + }); + + expect(result.current.deleteMemberActionList.aliveActionList).not.toContainEqual({ + actionId: 1, + name: '망쵸', + price: null, + sequence: 1, + }); + }); + + it('삭제할 멤버 목록에 있는 멤버들을 모두 삭제해 삭제할 멤버 목록을 비운다.', async () => { + const {result} = initializeProvider(); + + // stepList 값이 채워지길 대기합니다. + await waitFor(() => { + expect(result.current.stepListResult.data).not.toStrictEqual([]); + }); + + await act(async () => { + memberActionList.forEach(memberAction => { + result.current.deleteMemberActionList.addDeleteMemberAction(memberAction); + }); + }); + + await act(async () => result.current.deleteMemberActionList.deleteMemberActionList()); + + await waitFor(() => { + expect(result.current.deleteMemberActionList.aliveActionList).toHaveLength(0); + }); + }); + + it('삭제 요청에서 오류가 발생했을 경우 삭제할 멤버 목록을 처음의 상태로 돌려놓는다.', async () => { + /** + * 이 테스트는 deleteMemberAction을 실행했을 때 오류가 나는 경우를 테스트하기 위해 작성되었습니다. + * 여기서 사용하는 stepList 목데이터는 999 actionId를 가진 MemberAction이 있는 데이터입니다. + * 999 actionId는 현재 모킹되어있는 msw에서 오류를 뱉도록 하는 id입니다. 이는 오류 상황을 시연하기 위한 임의 모킹입니다. + * (999가 아닌 경우는 모두 정상 응답 반환) + */ + + // 999 actionId를 가진 MemberAction이 있는 stepListJson 데이터를 사용해 MemberActions []으로 정제합니다. + const invalidMemberStepListMockData = invalidMemberStepListJson as (BillStep | MemberStep)[]; + let memberActionList: MemberAction[] = []; + + for (let i = 0; i < invalidMemberStepListMockData.length; i++) { + const curAction = invalidMemberStepListMockData[i]; + if (curAction.type !== 'BILL') curAction.actions.forEach(action => memberActionList.push(action)); + } + + // 오류 멤버가 포함된 memberAction[]을 useDeleteMemberAction의 초기값으로 주입합니다. + const {result} = initializeProvider(memberActionList); + + // stepList 값이 채워지길 대기합니다. + await waitFor(() => { + expect(result.current.stepListResult.data).not.toStrictEqual([]); + }); + + await act(async () => { + const memberAction = memberActionList[0]; // 현재 0번 참여자는 actionId가 999 이고, 999 actionId는 서버에서 에러를 뱉도록 조작된 상황입니다. + result.current.deleteMemberActionList.addDeleteMemberAction(memberAction); + }); + + await act(async () => result.current.deleteMemberActionList.deleteMemberActionList()); + + // 삭제 요청에서 오류가 발생했기 때문에 aliveActionList를 초기에 주입했던 값으로 다시 돌려놓는지 확인합니다. + expect(result.current.deleteMemberActionList.aliveActionList).toStrictEqual(memberActionList); + }); +}); diff --git a/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx new file mode 100644 index 000000000..913087a59 --- /dev/null +++ b/client/src/hooks/useDeleteMemberAction/useDeleteMemberAction.tsx @@ -0,0 +1,86 @@ +import type {MemberAction} from 'types/serviceType'; + +import {useState} from 'react'; + +import useRequestGetStepList from '@hooks/queries/useRequestGetStepList'; +import useRequestDeleteMemberAction from '@hooks/queries/useRequestDeleteMemberAction'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; + +type UseDeleteMemberActionProps = { + memberActionList: MemberAction[]; + setIsBottomSheetOpened: React.Dispatch>; + showToastAlreadyExistMemberAction: () => void; + showToastExistSameMemberFromAfterStep: (name: string) => void; +}; + +const useDeleteMemberAction = ({ + memberActionList, + setIsBottomSheetOpened, + showToastAlreadyExistMemberAction, + showToastExistSameMemberFromAfterStep, +}: UseDeleteMemberActionProps) => { + const {data: stepListData} = useRequestGetStepList(); + const stepList = stepListData ?? []; + const {mutate: deleteMemberActionMutate} = useRequestDeleteMemberAction(); + + const [deleteActionList, setDeleteActionList] = useState([]); + + const eventId = getEventIdByUrl(); + + const deleteMemberAction = async (actionId: number) => { + deleteMemberActionMutate( + {actionId}, + { + onError: () => { + setDeleteActionList([]); + }, + }, + ); + setIsBottomSheetOpened(false); + }; + + // TODO: (@cookie: 추후에 반복문으로 delete하는 것이 아니라 한 번에 모아서 delete 처리하기 (backend에 문의)) + const deleteMemberActionList = async () => { + for (const {actionId} of deleteActionList) { + await deleteMemberAction(actionId); + } + }; + + const checkAlreadyExistMemberAction = (memberAction: MemberAction, showToast: () => void) => { + if (!memberActionList.includes(memberAction)) { + showToast(); + } + }; + + const checkExistSameMemberFromAfterStep = (memberAction: MemberAction, showToast: () => void) => { + if (isExistSameMemberFromAfterStep(memberAction)) { + showToast(); + } + }; + + const addDeleteMemberAction = (memberAction: MemberAction) => { + checkAlreadyExistMemberAction(memberAction, showToastAlreadyExistMemberAction); + checkExistSameMemberFromAfterStep(memberAction, () => showToastExistSameMemberFromAfterStep(memberAction.name)); + setDeleteActionList(prev => [...prev, memberAction]); + }; + + const isExistSameMemberFromAfterStep = (memberAction: MemberAction) => { + const memberActionList = stepList + .filter(step => step.type !== 'BILL') + .map(({actions}) => actions) + .flat(); + const currentActionIndex = memberActionList.findIndex(action => action.actionId === memberAction.actionId); + const memberActionListAfterCurrentAction = memberActionList.slice(Math.max(currentActionIndex - 1, 0)); + const memberNameList = memberActionListAfterCurrentAction.map(({name}) => name); + + return memberNameList.filter(member => member === memberAction.name).length >= 2; + }; + + const aliveActionList = memberActionList.filter( + memberAction => !deleteActionList.some(deleteAction => deleteAction.actionId === memberAction.actionId), + ); + return {aliveActionList, deleteMemberActionList, addDeleteMemberAction}; +}; + +export default useDeleteMemberAction; diff --git a/client/src/hooks/useDynamicInput.tsx b/client/src/hooks/useDynamicInput.tsx new file mode 100644 index 000000000..452add193 --- /dev/null +++ b/client/src/hooks/useDynamicInput.tsx @@ -0,0 +1,142 @@ +import {useEffect, useRef} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; + +import useInput from './useInput'; + +type InputValue = { + value: string; + index: number; +}; + +export type ReturnUseDynamicInput = { + inputList: InputValue[]; + inputRefList: React.MutableRefObject<(HTMLInputElement | null)[]>; + errorMessage: string | null; + canSubmit: boolean; + errorIndexList: number[]; + handleChange: (index: number, value: string) => void; + handleInputChange: (index: number, event: React.ChangeEvent) => void; + deleteEmptyInputElementOnBlur: () => void; + getFilledInputList: (list?: InputValue[]) => InputValue[]; + focusNextInputOnEnter: (e: React.KeyboardEvent, index: number) => void; + setInputValueTargetIndex: (index: number, value: string) => void; + resetInputValue: () => void; +}; + +const useDynamicInput = (validateFunc: (name: string) => ValidateResult): ReturnUseDynamicInput => { + const initialInputList = [{index: 0, value: ''}]; + const inputRefList = useRef<(HTMLInputElement | null)[]>([]); + + const {inputList, errorMessage, errorIndexList, canSubmit, handleChange, setInputList} = useInput({ + validateFunc, + initialInputList, + }); + + useEffect(() => { + if (inputRefList.current.length <= 0) return; + + const lastInput = inputRefList.current[inputRefList.current.length - 1]; + + if (lastInput) { + lastInput.scrollIntoView({behavior: 'smooth', block: 'center'}); + } + }, [inputList]); + + const handleInputChange = (index: number, event: React.ChangeEvent) => { + const {value} = event.target; + + makeNewInputWhenFirstCharacterInput(index, value); + handleChange(index, value); + }; + + const makeNewInputWhenFirstCharacterInput = (index: number, value: string) => { + if (isLastInputFilled(index, value) && value.trim().length !== 0) { + // 마지막 인풋이 한 자라도 채워진다면 새로운 인풋을 생성해 간편한 다음 입력을 유도합니다. + setInputList(prevInputs => { + const updatedInputList = [...prevInputs]; + + // 새로운 인덱스를 inputs 배열 길이를 기준으로 설정 + const newIndex = updatedInputList[updatedInputList.length - 1].index + 1; + + return [...updatedInputList, {index: newIndex, value: ''}]; + }); + } + }; + + const deleteEmptyInputElementOnBlur = () => { + // 0, 1번 input이 값이 있는 상태에서 두 input의 값을 모두 x버튼으로 제거해도 input이 2개 남아있는 문제를 위해 조건문을 추가했습니다. + if (getFilledInputList().length === 0 && inputList.length > 1) { + setInputList([{index: 0, value: ''}]); + return; + } + + // *표시 조건문은 처음에 input을 클릭했다가 블러시켰을 때 filledInputList가 아예 없어 .index에 접근할 때 오류가 납니다. 이를 위한 얼리리턴을 두었습니다. + if (getFilledInputList().length === 0) return; + + if (getFilledInputList().length !== inputList.length) { + setInputList(inputList => { + const filledInputList = getFilledInputList(inputList); + + // 새 입력의 인덱스를 inputs 길이를 기준으로 설정 + const newIndex = filledInputList[filledInputList.length - 1].index + 1; + + return [...filledInputList, {index: newIndex, value: ''}]; + }); + } + }; + + const setInputValueTargetIndex = (index: number, value: string) => { + setInputList(prevInputs => { + const updatedInputList = [...prevInputs]; + const targetInput = findInputByIndex(index, updatedInputList); + + targetInput.value = value; + + return updatedInputList; + }); + }; + + const resetInputValue = () => { + setInputList(initialInputList); + }; + + const focusNextInputOnEnter = (e: React.KeyboardEvent, index: number) => { + if (e.nativeEvent.isComposing) return; + + if (e.key === 'Enter') { + inputRefList.current[index + 1]?.focus(); + } + }; + + const findInputByIndex = (index: number, list?: InputValue[]) => { + return (list ?? inputList).filter(input => input.index === index)[0]; + }; + + const getFilledInputList = (list?: InputValue[]) => { + return (list ?? inputList).filter(({value}) => value.trim().length !== 0); + }; + + const isLastInputFilled = (index: number, value: string) => { + const lastInputIndex = inputList[inputList.length - 1].index; + + return value !== '' && index === lastInputIndex; + }; + + return { + inputList, + inputRefList, + errorMessage, + canSubmit, + errorIndexList, + handleInputChange, + handleChange, + deleteEmptyInputElementOnBlur, + getFilledInputList, + focusNextInputOnEnter, + setInputValueTargetIndex, + resetInputValue, + }; +}; + +export default useDynamicInput; diff --git a/client/src/hooks/useEventLogin.ts b/client/src/hooks/useEventLogin.ts new file mode 100644 index 000000000..ccabe20c1 --- /dev/null +++ b/client/src/hooks/useEventLogin.ts @@ -0,0 +1,42 @@ +import {useState} from 'react'; + +import validateEventPassword from '@utils/validate/validateEventPassword'; + +import RULE from '@constants/rule'; + +import useRequestPostLogin from './queries/useRequestPostLogin'; + +const useEventLogin = () => { + const [password, setPassword] = useState(''); + const [errorMessage, setErrorMessage] = useState(null); + const [canSubmit, setCanSubmit] = useState(false); + const {mutate: postLogin} = useRequestPostLogin(); + + const submitPassword = async (event: React.FormEvent) => { + event.preventDefault(); + + postLogin({password}, {onError: () => setErrorMessage('비밀번호가 틀렸어요')}); + }; + + const handleChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + const validation = validateEventPassword(newValue); + setErrorMessage(validation.errorMessage); + + if (validation.isValid) { + setPassword(newValue); + } + + setCanSubmit(newValue.length === RULE.maxEventPasswordLength); + }; + + return { + password, + errorMessage, + handleChange, + canSubmit, + submitPassword, + }; +}; + +export default useEventLogin; diff --git a/client/src/hooks/useInput.tsx b/client/src/hooks/useInput.tsx new file mode 100644 index 000000000..a6901573b --- /dev/null +++ b/client/src/hooks/useInput.tsx @@ -0,0 +1,97 @@ +import {useEffect, useState} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; + +import {ERROR_MESSAGE} from '@constants/errorMessage'; + +export type InputValue = { + value: string; + index?: number; +}; + +export type UseInputReturn = { + inputList: T[]; + errorMessage: string; + errorIndexList: number[]; + canSubmit: boolean; + handleChange: (index: number, value: string) => void; + setInputList: React.Dispatch>; + addErrorIndex: (index: number) => void; + setCanSubmit: React.Dispatch>; +}; + +type UseInputProps = { + validateFunc: (value: string) => ValidateResult; + initialInputList: T[]; +}; + +const useInput = ({validateFunc, initialInputList}: UseInputProps): UseInputReturn => { + const [inputList, setInputList] = useState(initialInputList); + const [errorMessage, setErrorMessage] = useState(''); + const [errorIndexList, setErrorIndexList] = useState([]); + const [canSubmit, setCanSubmit] = useState(false); + + useEffect(() => { + changeCanSubmit(); + }, [errorMessage, errorIndexList]); + + useEffect(() => { + setInputList(prev => prev.map((value, index) => ({...value, index}))); + }, [inputList.length]); + + const handleChange = (index: number = 0, value: string) => { + const {isValid, errorMessage: validationResultMessage} = validateFunc(value); + + if (validationResultMessage === ERROR_MESSAGE.preventEmpty) { + setErrorMessage(validationResultMessage); + updateInputList(index, value); + addErrorIndex(index); + } else if (isValid && value.length !== 0) { + // TODO: (@soha) 쿠키가 작업한 errorMessage를 위로 올리기 변경 추후에 merge후에 반영하기 + setErrorMessage(''); + updateInputList(index, value); + removeErrorIndex(index); + } + }; + + const updateInputList = (index: number, value: string) => { + setInputList(prev => { + const newList = [...prev]; + const targetInput = newList.find(input => input.index === index); + if (targetInput) { + targetInput.value = value; + } + return newList; + }); + }; + + const removeErrorIndex = (index: number) => { + setErrorIndexList(prev => prev.filter(i => i !== index)); + }; + + const addErrorIndex = (index: number) => { + setErrorIndexList(prev => { + if (!prev.includes(index)) { + return [...prev, index]; + } + return prev; + }); + }; + + const changeCanSubmit = () => { + setCanSubmit(errorIndexList.length || errorMessage.length ? false : true); + }; + + return { + inputList, + errorMessage, + errorIndexList, + canSubmit, + handleChange, + setInputList, + addErrorIndex, + setCanSubmit, + }; +}; + +export default useInput; diff --git a/client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx b/client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx new file mode 100644 index 000000000..9c9cd80d9 --- /dev/null +++ b/client/src/hooks/useMemberReportListInAction/useMemberReportInput.tsx @@ -0,0 +1,89 @@ +import type {MemberReportInAction} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import validateMemberReportInAction from '@utils/validate/validateMemberReportInAction'; + +type MemberReportInput = MemberReportInAction & { + index: number; +}; + +type UseMemberReportProps = { + data: MemberReportInAction[]; + addAdjustedMember: (memberReport: MemberReportInAction) => void; + getOnlyOneNotAdjustedRemainMemberIndex: () => number | null; + getIsSamePriceStateAndServerState: () => boolean; + totalPrice: number; +}; + +const useMemberReportInput = ({ + data, + addAdjustedMember, + totalPrice, + getOnlyOneNotAdjustedRemainMemberIndex, + getIsSamePriceStateAndServerState, +}: UseMemberReportProps) => { + const [inputList, setInputList] = useState(data.map((item, index) => ({...item, index}))); + const [canSubmit, setCanSubmit] = useState(false); + + const [canEditList, setCanEditList] = useState([]); + + const onChange = (event: React.ChangeEvent, index: number) => { + const {value} = event.target; + + validateAndAddAdjustedMember(value, index); + }; + + const validateAndAddAdjustedMember = (price: string, index: number) => { + const {isValid} = validateMemberReportInAction(price, totalPrice); + + if (isValid) { + const newInputList = [...inputList]; + newInputList[index].price = Number(price); + setInputList(newInputList); + + const memberReportData: MemberReportInAction = { + name: newInputList[index].name, + price: newInputList[index].price, + isFixed: newInputList[index].isFixed, + }; + addAdjustedMember(memberReportData); + } + }; + + // 서버와 값이 같지 않고 input price의 상태가 모두 valid하다면 can submit true + useEffect(() => { + const isSamePriceState = getIsSamePriceStateAndServerState(); + const isAllValid = inputList.every(input => validateMemberReportInAction(String(input.price), totalPrice)); + + setCanSubmit(!isSamePriceState && isAllValid); + }, [inputList]); + + // addAdjustedMember로 인해 data가 변했을 때 input list의 값을 맞춰주기 위함 + useEffect(() => { + setCanSubmit(!getIsSamePriceStateAndServerState()); + setInputList(data.map((item, index) => ({...item, index}))); + + // 남은 인원이 1명일 때 수정을 불가능하도록 설정 + const onlyOneIndex = getOnlyOneNotAdjustedRemainMemberIndex(); + + if (data.length !== 0) { + setCanEditList(new Array(data.length).fill(true)); + } + + if (onlyOneIndex !== null) { + const newCanEditList = new Array(data.length).fill(true); + newCanEditList[onlyOneIndex] = false; + setCanEditList(newCanEditList); + } + }, [data]); + + return { + inputList, + onChange, + canEditList, + canSubmit, + }; +}; + +export default useMemberReportInput; diff --git a/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx new file mode 100644 index 000000000..78c29ee03 --- /dev/null +++ b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.test.tsx @@ -0,0 +1,327 @@ +import type {MemberReportInAction} from 'types/serviceType'; + +import {renderHook, waitFor, act} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; +import {QueryClient, QueryClientProvider} from '@tanstack/react-query'; + +import memberReportListInActionJson from '../../mocks/memberReportListInAction.json'; + +import useMemberReportListInAction from './useMemberReportListInAction'; + +describe('useMemberReportListInActionTest', () => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: 0, + }, + }, + }); + + const initializeProvider = (actionId: number, totalPrice: number) => + renderHook(() => useMemberReportListInAction(actionId, totalPrice, () => {}), { + wrapper: ({children}) => ( + + {children} + + ), + }); + + const actionId = 123; + const totalPrice = 100000; + + describe('Flow: 유저가 정상적으로 값을 불러왔을 때의 test', () => { + it('초기값을 정상적으로 불러온다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + expect(result.current.memberReportListInAction).toStrictEqual(memberReportListInActionJson); + }); + + it('망쵸의 가격을 100원으로 바꾸면 망쵸의 가격은 100원으로 설정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMember: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMember); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '망쵸'); + + expect(targetMember?.price).toBe(100); + }); + + it('망쵸의 가격을 100원으로 바꾸면 망쵸의 가격은 100원으로 설정되고 나머지 인원의 가격이 33,300원으로 설정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMember: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMember); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '망쵸'); + expect(targetMember?.price).toBe(100); + + const anotherMemberList = result.current.memberReportListInAction.filter(member => member.name !== '망쵸'); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(33300); + }); + }); + + it('망쵸의 가격을 100원 쿠키의 가격을 100원으로 바꾸면 나머지 인원의 가격이 49,900원으로 설정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + const adjustedMemberCookie: MemberReportInAction = {name: '쿠키', price: 100, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookie); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter( + member => !(member.name === '망쵸' || member.name === '쿠키'), + ); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(49900); + }); + }); + + it('망쵸의 가격을 100원 쿠키의 가격을 100원으로 바꾸면 나머지 인원의 가격이 49,900원으로 설정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + const adjustedMemberCookie: MemberReportInAction = {name: '쿠키', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookie); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter( + member => !(member.name === '망쵸' || member.name === '쿠키'), + ); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(49900); + }); + }); + + it('망쵸의 가격을 100원으로 바꾸고 다시 망쵸의 가격을 10,000원으로 바꾸면 나머지 인원의 가격이 30,000원으로 설정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + const adjustedMemberMangchoAfter: MemberReportInAction = {name: '망쵸', price: 10000, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangchoAfter); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter(member => member.name !== '망쵸'); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(30000); + }); + }); + }); + + describe('예외 & 엣지케이스', () => { + it('동일한 인원의 가격을 동일하게 바꾸면 변함없다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember({...adjustedMemberMangcho, isFixed: true}); + }); + + const anotherMemberList = result.current.memberReportListInAction.filter(member => member.name !== '망쵸'); + + expect(anotherMemberList[0].price).toBe(33300); + }); + + it('망쵸에게 300원을 주면 나머지 사람들은 33233원이고 마지막 사람은 33234원이 된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 300, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '망쵸'); + expect(targetMember?.price).toBe(300); + + const anotherMemberList = result.current.memberReportListInAction.filter( + member => member.name === '이상' || member.name === '소하', + ); + + anotherMemberList.forEach(member => { + expect(member.price).toBe(33233); + }); + + const lastMember = result.current.memberReportListInAction.find(member => member.name === '쿠키'); + + expect(lastMember?.price).toBe(33234); + }); + + it('망쵸, 쿠키의 가격을 100원으로 바꾼 후 다시 쿠키의 가격을 33000원으로 바꾸면 쿠키의 isFixed는 false가 된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + const adjustedMemberCookie: MemberReportInAction = {name: '쿠키', price: 100, isFixed: false}; + const adjustedMemberCookieReset: MemberReportInAction = {name: '쿠키', price: 33300, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookie); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '쿠키'); + + expect(targetMember?.isFixed).toBe(true); + + act(() => { + result.current.addAdjustedMember(adjustedMemberCookieReset); + }); + + const targetMemberReset = result.current.memberReportListInAction.find(member => member.name === '쿠키'); + + expect(targetMemberReset?.isFixed).toBe(false); + }); + + it('망쵸의 가격을 100원으로 바꾼 후 다시 망쵸의 가격을 25000원으로 바꾸면 망쵸의 isFixed는 false가 된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + const adjustedMemberMangchoAfter: MemberReportInAction = {name: '망쵸', price: 25000, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '망쵸'); + expect(targetMember?.isFixed).toBe(true); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangchoAfter); + }); + + const targetMemberReset = result.current.memberReportListInAction.find(member => member.name === '망쵸'); + expect(targetMemberReset?.isFixed).toBe(false); + }); + + it('아무도 조정된 값이 없다면 조정값이 있는지 확인 결과 false다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + expect(result.current.isExistAdjustedPrice()).toBe(false); + }); + + it('망쵸의 가격을 100원으로 바꾼 후 리스트 중 조정값이 있는지 확인 결과 true다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + expect(result.current.isExistAdjustedPrice()).toBe(true); + }); + }); + + describe('지출 인원이 2명인 상황', () => { + const actionId = 1; + const totalPrice = 50000; + + // 망쵸 이상 + it('망쵸의 가격을 100원으로 수정한 경우, 이상의 가격이 49900원으로 수정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '이상'); + + expect(targetMember?.price).toBe(49900); + }); + + it('망쵸의 가격을 100원으로 수정하고 다시 200원으로 수정한 경우, 이상의 가격이 49800원으로 수정된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + const adjustedMemberMangchoOther: MemberReportInAction = {name: '망쵸', price: 200, isFixed: true}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangchoOther); + }); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '이상'); + + expect(targetMember?.price).toBe(49800); + }); + }); + + // last + describe('onSubmit 실행 시 반영 테스트', () => { + it('망쵸의 가격을 100원으로 바꾸고 저장하면 망쵸 100원이 반영된다.', async () => { + const {result} = initializeProvider(actionId, totalPrice); + const adjustedMemberMangcho: MemberReportInAction = {name: '망쵸', price: 100, isFixed: false}; + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + act(() => { + result.current.addAdjustedMember(adjustedMemberMangcho); + }); + + await waitFor(() => { + result.current.onSubmit(); + }); + + await waitFor(() => expect(result.current.queryResult.isSuccess).toBe(true)); + + const targetMember = result.current.memberReportListInAction.find(member => member.name === '망쵸'); + expect(targetMember?.price).toBe(100); + }); + }); +}); diff --git a/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts new file mode 100644 index 000000000..0e32d740c --- /dev/null +++ b/client/src/hooks/useMemberReportListInAction/useMemberReportListInAction.ts @@ -0,0 +1,156 @@ +import type {MemberReportInAction} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import useRequestGetMemberReportListInAction from '@hooks/queries/useRequestGetMemberReportListInAction'; +import useRequestPutMemberReportListInAction from '@hooks/queries/useRequestPutMemberReportListInAction'; + +const useMemberReportListInAction = (actionId: number, totalPrice: number, onClose: () => void) => { + const {memberReportListInActionFromServer, queryResult} = useRequestGetMemberReportListInAction(actionId); + const {putMemberReportListInAction} = useRequestPutMemberReportListInAction(actionId); + + const [memberReportListInAction, setMemberReportListInAction] = useState( + memberReportListInActionFromServer, + ); + + // isFixed를 모두 풀고 계산값으로 모두 처리하는 기능 + const reCalculatePriceByTotalPriceChange = () => { + const {divided, remainder} = calculateDividedPrice(memberReportListInAction.length, 0); + + const resetMemberReportList = [...memberReportListInAction]; + resetMemberReportList.forEach((member, index) => { + if (index !== resetMemberReportList.length - 1) { + member.price = divided; + } else { + member.price = divided + remainder; + } + member.isFixed = false; + }); + + setMemberReportListInAction(resetMemberReportList); + }; + + // 총 금액이 변동됐을 때 (서버에서 온 값과 다를 때) 재계산 실행 + useEffect(() => { + const totalPriceFromServer = memberReportListInActionFromServer.reduce((acc, cur) => acc + cur.price, 0); + + if (totalPriceFromServer !== totalPrice && totalPriceFromServer !== 0) { + reCalculatePriceByTotalPriceChange(); + } + }, [totalPrice, memberReportListInActionFromServer]); + + useEffect(() => { + if (queryResult.isSuccess) { + setMemberReportListInAction(memberReportListInActionFromServer); + } + }, [memberReportListInActionFromServer, queryResult.isSuccess]); + + const isExistAdjustedPrice = () => { + return memberReportListInAction.some(member => member.isFixed === true); + }; + + // 조정되지 않은 인원이 단 1명인 경우의 index + const getOnlyOneNotAdjustedRemainMemberIndex = (): number | null => { + const adjustedPriceCount = getAdjustedMemberCount(memberReportListInAction); + + if (adjustedPriceCount < memberReportListInAction.length - 1) return null; + + return memberReportListInAction.findIndex(member => member.isFixed === false); + }; + + // 조정값 멤버의 수를 구하는 함수 + const getAdjustedMemberCount = (memberReportListInAction: MemberReportInAction[]) => { + return memberReportListInAction.filter(member => member.isFixed === true).length; + }; + + const addAdjustedMember = (memberReport: MemberReportInAction) => { + const newMemberReportListInAction = memberReportListInAction.map(member => + member.name === memberReport.name ? {...member, price: memberReport.price, isFixed: true} : member, + ); + + calculateAnotherMemberPrice(newMemberReportListInAction); + }; + + const calculateDividedPrice = (remainMemberCount: number, totalAdjustedPrice: number) => { + return { + divided: Math.floor((totalPrice - totalAdjustedPrice) / remainMemberCount), + remainder: (totalPrice - totalAdjustedPrice) % remainMemberCount, + }; + }; + + // 계산값으로 값을 변경했을 때 isFixed를 푸는 함수 + // 100 true 33300 true 33300 false 33300 false + const setIsFixedFalseAtResetToDividedPrice = (memberReportListInAction: MemberReportInAction[], divided: number) => { + return memberReportListInAction.map(memberReport => { + if (memberReport.isFixed === true && memberReport.price === divided) { + return {...memberReport, isFixed: false}; + } + + return memberReport; + }); + }; + + const calculateAnotherMemberPrice = (memberReportListInAction: MemberReportInAction[]) => { + // 총 조정치 금액 + const totalAdjustedPrice = memberReportListInAction + .filter(memberReport => memberReport.isFixed === true) + .reduce((acc, cur) => acc + cur.price, 0); + + const remainMemberCount = memberReportListInAction.length - getAdjustedMemberCount(memberReportListInAction); + const {divided, remainder} = calculateDividedPrice(remainMemberCount, totalAdjustedPrice); + + const updatedList = memberReportListInAction.map(member => + member.isFixed === true ? member : {...member, price: divided}, + ); + + // 나머지를 조정되지 않은 멤버 중 마지막 멤버에게 추가 + if (remainder !== 0) { + const nonAdjustedMembers = updatedList.filter(member => member.isFixed === false); + const lastNonAdjustedMemberIndex = updatedList.findIndex( + member => member.name === nonAdjustedMembers[nonAdjustedMembers.length - 1].name, + ); + + if (lastNonAdjustedMemberIndex !== -1) { + updatedList[lastNonAdjustedMemberIndex].price += remainder; + } + } + + // 조정됐지만 계산값으로 가격이 변한 경우 fixed 상태를 풀어야한다. + const result = setIsFixedFalseAtResetToDividedPrice(updatedList, divided); + setMemberReportListInAction(result); + }; + + const onSubmit = () => { + putMemberReportListInAction(memberReportListInAction); + + onClose(); + }; + + const getIsSamePriceStateAndServerState = () => { + const serverStatePriceList = memberReportListInActionFromServer.map(({price}) => price); + const clientStatePriceList = memberReportListInAction.map(({price}) => price); + + let isSame = true; + + // isArrayEqual을 사용하지 않은 이유는 정렬이 영향을 받으면 안 되기 때문입니다 + for (let i = 0; i < serverStatePriceList.length; i++) { + if (serverStatePriceList[i] !== clientStatePriceList[i]) { + isSame = false; + } + } + + return isSame; + }; + + return { + memberReportListInAction, + addAdjustedMember, + isExistAdjustedPrice, + onSubmit, + getOnlyOneNotAdjustedRemainMemberIndex, + getIsSamePriceStateAndServerState, + queryResult, + }; +}; + +export default useMemberReportListInAction; diff --git a/client/src/hooks/useNavSwitch.tsx b/client/src/hooks/useNavSwitch.tsx new file mode 100644 index 000000000..a622a7a30 --- /dev/null +++ b/client/src/hooks/useNavSwitch.tsx @@ -0,0 +1,42 @@ +import {useEffect, useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; + +const PATH_TABLE: Record = { + 홈: 'home', + 관리: 'admin', +}; + +const PATH_DISPLAY_TABLE: Record = { + home: '홈', + admin: '관리', +}; + +const useNavSwitch = () => { + const paths = ['홈', '관리']; + const location = useLocation(); + const navigate = useNavigate(); + + const pathArray = location.pathname.split('/'); + const basePath = pathArray.slice(0, -1).join('/'); + const lastPath = pathArray[pathArray.length - 1]; + + const [nav, setNav] = useState(PATH_DISPLAY_TABLE[lastPath]); + + useEffect(() => { + const isLogin = lastPath === 'login'; + setNav(isLogin ? '관리' : PATH_DISPLAY_TABLE[lastPath]); + }, [location]); + + const onChange = (displayName: string) => { + setNav(displayName); + navigate(`${basePath}/${PATH_TABLE[displayName]}`); + }; + + return { + nav, + paths, + onChange, + }; +}; + +export default useNavSwitch; diff --git a/client/src/hooks/usePutAndDeleteBillAction.ts b/client/src/hooks/usePutAndDeleteBillAction.ts new file mode 100644 index 000000000..6f1e4feaf --- /dev/null +++ b/client/src/hooks/usePutAndDeleteBillAction.ts @@ -0,0 +1,113 @@ +import type {Bill, BillInputType, InputPair} from 'types/serviceType'; + +import {useEffect, useState} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; + +import {ERROR_MESSAGE} from '@constants/errorMessage'; + +import usePutBillAction from './queries/useRequestPutBillAction'; +import useDeleteBillAction from './queries/useRequestDeleteBillAction'; + +const usePutAndDeleteBillAction = ( + initialValue: InputPair, + validateFunc: (inputPair: Bill) => ValidateResult, + onClose: () => void, +) => { + const [inputPair, setInputPair] = useState(initialValue); + const [canSubmit, setCanSubmit] = useState(false); + const [errorInfo, setErrorInfo] = useState>({title: false, price: false}); + const [errorMessage, setErrorMessage] = useState(null); + + const {mutateAsync: putBillAction} = usePutBillAction(); + const {mutate: deleteBillAction} = useDeleteBillAction(); + + // 현재 타겟의 event.target.value를 넣어주기 위해서 + const getFieldValue = (field: BillInputType, value: string) => { + if (field === 'title') { + return {title: value, price: Number(inputPair.price)}; + } else { + return {title: inputPair.title, price: Number(value)}; + } + }; + + // TODO: (@weadie) getFieldValue 를 리펙토링해야한다. + + const handleInputChange = (field: BillInputType, event: React.ChangeEvent) => { + const {value} = event.target; + + const {isValid, errorMessage, errorInfo} = validateFunc(getFieldValue(field, value)); + + setErrorMessage(errorMessage); + + if (isValid) { + // valid일 경우 에러메시지 nope, setValue, submit은 value가 비지 않았을 때 true를 설정 + setInputPair(prevInputPair => { + return { + ...prevInputPair, + [field]: value, + }; + }); + setCanSubmit(value.length !== 0); + } else { + const {isValid: isValidName} = validateFunc(getFieldValue('title', inputPair.title)); + const {isValid: isValidPrice} = validateFunc(getFieldValue('price', inputPair.price)); + + setCanSubmit(isValidName && isValidPrice); + // valid하지 않으면 event.target.value 덮어쓰기 + event.target.value = inputPair[field]; + } + + if (field === 'title') { + // 현재 field가 title일 때는 title의 errorInfo만 반영해줌 (blur에서도 errorInfo를 조작하기 때문) + setErrorInfo(prev => ({title: errorInfo?.title ?? false, price: prev.price})); + } else { + setErrorInfo(prev => ({title: prev.title, price: errorInfo?.price ?? false})); + } + }; + + const handleOnBlur = () => { + const {isValid, errorMessage, errorInfo} = validateFunc({title: inputPair.title, price: Number(inputPair.price)}); + + // blur시 값이 비었을 때 error state 반영 + if (inputPair.price.length === 0 || inputPair.title.length === 0) { + setErrorMessage(ERROR_MESSAGE.preventEmpty); + setErrorInfo({title: inputPair.title.length === 0, price: inputPair.price.length === 0}); + setCanSubmit(false); + return; + } + + // 이외 blur시에 추가로 검증함 + setErrorMessage(errorMessage); + setCanSubmit(isValid); + setErrorInfo(errorInfo ?? {title: false, price: false}); + }; + + const onSubmit = async (event: React.FormEvent, inputPair: InputPair, actionId: number) => { + event.preventDefault(); + + const {title, price} = inputPair; + + await putBillAction({actionId, title, price: Number(price)}); + + onClose(); + }; + + const onDelete = async (actionId: number) => { + deleteBillAction({actionId}); + onClose(); + }; + + return { + inputPair, + handleInputChange, + handleOnBlur, + onSubmit, + onDelete, + canSubmit, + errorMessage, + errorInfo, + }; +}; + +export default usePutAndDeleteBillAction; diff --git a/client/src/hooks/useSearchInMemberList.ts b/client/src/hooks/useSearchInMemberList.ts new file mode 100644 index 000000000..09f227b8e --- /dev/null +++ b/client/src/hooks/useSearchInMemberList.ts @@ -0,0 +1,54 @@ +import {useState} from 'react'; + +import useRequestGetCurrentInMemberList from './queries/useRequestGetCurrentInMemberList'; + +export type ReturnUseSearchInMemberList = { + currentInputIndex: number; + handleCurrentInputIndex: (inputIndex: number) => void; + filteredInMemberList: string[]; + searchCurrentInMember: (event: React.ChangeEvent) => void; + chooseMember: (inputIndex: number, name: string) => void; +}; + +const useSearchInMemberList = (handleChange: (index: number, value: string) => void): ReturnUseSearchInMemberList => { + const [currentInputIndex, setCurrentInputIndex] = useState(-1); + + // 서버에서 가져온 전체 리스트 + const {data} = useRequestGetCurrentInMemberList(); + const currentInMemberList = data?.memberNames ?? []; + + // 검색된 리스트 (따로 둔 이유는 검색 후 클릭했을 때 리스트를 비워주어야하기 때문) + const [filteredInMemberList, setFilteredInMemberList] = useState>([]); + + const filterMatchItems = (keyword: string) => { + if (keyword.trim() === '') return []; + + return currentInMemberList + .filter(member => member.toLocaleLowerCase().indexOf(keyword.toLocaleLowerCase()) > -1) + .slice(0, 3); + }; + + const chooseMember = (inputIndex: number, name: string) => { + setFilteredInMemberList([]); + handleChange(inputIndex, name); + }; + + const searchCurrentInMember = (event: React.ChangeEvent) => { + const {value} = event.target; + setFilteredInMemberList(filterMatchItems(value)); + }; + + const handleCurrentInputIndex = (inputIndex: number) => { + setCurrentInputIndex(inputIndex); + }; + + return { + currentInputIndex, + handleCurrentInputIndex, + filteredInMemberList, + searchCurrentInMember, + chooseMember, + }; +}; + +export default useSearchInMemberList; diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx new file mode 100644 index 000000000..90782cbdf --- /dev/null +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.test.tsx @@ -0,0 +1,41 @@ +import {renderHook, waitFor} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; + +import AppErrorBoundary from '@components/AppErrorBoundary/ErrorCatcher'; +import QueryClientBoundary from '@components/QueryClientBoundary/QueryClientBoundary'; +import {ToastProvider} from '@hooks/useToast/ToastProvider'; + +import reportListJson from '../../mocks/reportList.json'; + +import useSearchMemberReportList from './useSearchMemberReportList'; + +describe('useSearchMemberReportList', () => { + const initializeProvider = (name: string) => + renderHook(() => useSearchMemberReportList({name}), { + wrapper: ({children}) => ( + + + + {children} + + + + ), + }); + + it('빈 값을 검색한다면 검색 목록은 비어있다.', async () => { + const {result} = initializeProvider(''); + + await waitFor(() => expect(result.current.memberReportSearchList).toStrictEqual(reportListJson)); + }); + + it('검색어의 일부와 일치하는 이름이 있다면 해당 이름을 목록에 반환한다.', async () => { + const keyword = '소'; + const {result} = initializeProvider(keyword); + const expectedMemberReportSearchList = reportListJson.filter(memberReport => memberReport.name.includes(keyword)); + + await waitFor(() => { + expect(result.current.memberReportSearchList).toStrictEqual(expectedMemberReportSearchList); + }); + }); +}); diff --git a/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx new file mode 100644 index 000000000..4a967e45c --- /dev/null +++ b/client/src/hooks/useSearchMemberReportList/useSearchMemberReportList.tsx @@ -0,0 +1,16 @@ +import useRequestGetMemberReportList from '@hooks/queries/useRequestGetMemberReportList'; + +type UseSearchMemberReportListParams = { + name: string; +}; + +const useSearchMemberReportList = ({name}: UseSearchMemberReportListParams) => { + const {data} = useRequestGetMemberReportList(); + const memberReportList = data ?? []; + + return { + memberReportSearchList: memberReportList.filter(memberReport => memberReport.name.includes(name)), + }; +}; + +export default useSearchMemberReportList; diff --git a/client/src/hooks/useSetAllMemberList.tsx b/client/src/hooks/useSetAllMemberList.tsx new file mode 100644 index 000000000..02241d3e3 --- /dev/null +++ b/client/src/hooks/useSetAllMemberList.tsx @@ -0,0 +1,100 @@ +import {useEffect, useState} from 'react'; + +import {ValidateResult} from '@utils/validate/type'; +import {MemberChange} from '@apis/request/member'; + +import isArraysEqual from '@utils/isArraysEqual'; + +import useDeleteAllMemberList from './queries/useRequestDeleteAllMemberList'; +import usePutAllMemberList from './queries/useRequestPutAllMemberList'; +import useInput from './useInput'; + +interface UseSetAllMemberListProps { + validateFunc: (name: string) => ValidateResult; + allMemberList: string[]; + handleCloseAllMemberListModal: () => void; +} + +interface UseSetAllMemberListReturns { + editedAllMemberList: string[]; + canSubmit: boolean; + errorMessage: string; + errorIndexList: number[]; + handleNameChange: (index: number, event: React.ChangeEvent) => void; + handleClickDeleteButton: (index: number) => Promise; + handlePutAllMemberList: () => Promise; +} + +const useSetAllMemberList = ({ + validateFunc, + allMemberList, + handleCloseAllMemberListModal, +}: UseSetAllMemberListProps): UseSetAllMemberListReturns => { + const initialInputList = allMemberList.map((name, index) => ({index, value: name})); + const { + inputList, + errorMessage, + errorIndexList, + canSubmit, + handleChange, + setInputList: setEditedAllMemberList, + setCanSubmit, + } = useInput({validateFunc, initialInputList}); + + const [deleteInOriginal, setDeleteInOriginal] = useState(allMemberList); + const [deleteMemberList, setDeleteMemberList] = useState([]); + + const {mutateAsync: deleteAllMemberList} = useDeleteAllMemberList(); + const {mutate: putAllMemberList} = usePutAllMemberList(); + + const editedAllMemberList = inputList.map(input => input.value); + + useEffect(() => { + setCanSubmit(!isArraysEqual(editedAllMemberList, allMemberList)); + }, [editedAllMemberList]); + + const handleNameChange = (index: number, event: React.ChangeEvent) => { + const {value} = event.target; + + handleChange(index, value); + }; + + const handleClickDeleteButton = async (index: number) => { + const memberToDelete = editedAllMemberList[index]; + + setDeleteMemberList(prev => [...prev, memberToDelete]); + setDeleteInOriginal(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]); + setEditedAllMemberList(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]); + }; + + const handlePutAllMemberList = async () => { + // deleteMemberList가 비어있지 않은 경우에만 반복문 실행 (삭제 api 요청) + if (deleteMemberList.length > 0) { + for (const deleteMember of deleteMemberList) { + await deleteAllMemberList({memberName: deleteMember}); + } + } + + const editedMemberName: MemberChange[] = deleteInOriginal + .map((originalName, index) => { + if (editedAllMemberList[index] !== originalName) { + return {before: originalName, after: editedAllMemberList[index]}; + } + return null; // 조건에 맞지 않으면 null을 반환 + }) + .filter(item => item !== null); // null인 항목을 필터링하여 제거 + if (!isArraysEqual(editedAllMemberList, deleteInOriginal)) putAllMemberList({members: editedMemberName}); + handleCloseAllMemberListModal(); + }; + + return { + editedAllMemberList, + canSubmit, + errorMessage, + errorIndexList, + handleNameChange, + handleClickDeleteButton, + handlePutAllMemberList, + }; +}; +export default useSetAllMemberList; diff --git a/client/src/hooks/useSetBillInput.ts b/client/src/hooks/useSetBillInput.ts new file mode 100644 index 000000000..a14b2a481 --- /dev/null +++ b/client/src/hooks/useSetBillInput.ts @@ -0,0 +1,67 @@ +import {useState} from 'react'; + +import validatePurchase from '@utils/validate/validatePurchase'; +import {Bill, BillInputType} from 'types/serviceType'; + +import useRequestPostBillList from './queries/useRequestPostBillList'; + +interface UseSetBillInputProps { + setIsAddEditableItem: React.Dispatch>; +} + +interface UseSetBillInputReturns { + billInput: Bill; + handleChangeBillInput: (field: BillInputType, event: React.ChangeEvent) => void; + handleBlurBillRequest: () => void; +} + +const useSetBillInput = ({setIsAddEditableItem}: UseSetBillInputProps): UseSetBillInputReturns => { + const initialInput = {title: '', price: 0}; + const [billInput, setBillInput] = useState(initialInput); + + const {mutate: postBillList} = useRequestPostBillList(); + + const handleChangeBillInput = (field: BillInputType, event: React.ChangeEvent) => { + const {value} = event.target; + const {isValid} = validatePurchase({ + ...billInput, + [field]: value, + }); + + if (isValid) { + setBillInput(prev => ({ + ...prev, + [field]: value, + })); + } + }; + + const handleBlurBillRequest = () => { + const isEmptyTitle = billInput.title.trim().length; + const isEmptyPrice = Number(billInput.price); + + // 두 input의 값이 모두 채워졌을 때 api 요청 + // api 요청을 하면 Input을 띄우지 않음 + if (isEmptyTitle && isEmptyPrice) { + postBillList( + {billList: [billInput]}, + { + onSuccess: () => { + setBillInput(initialInput); + setIsAddEditableItem(false); + }, + }, + ); + } else if (!isEmptyTitle && !isEmptyPrice) { + setIsAddEditableItem(false); + } + }; + + return { + billInput, + handleBlurBillRequest, + handleChangeBillInput, + }; +}; + +export default useSetBillInput; diff --git a/client/src/hooks/useSetEventNamePage.ts b/client/src/hooks/useSetEventNamePage.ts new file mode 100644 index 000000000..f5b5bce12 --- /dev/null +++ b/client/src/hooks/useSetEventNamePage.ts @@ -0,0 +1,32 @@ +import {useState} from 'react'; + +import validateEventName from '@utils/validate/validateEventName'; + +const useSetEventNamePage = () => { + const [eventName, setEventName] = useState(''); + const [errorMessage, setErrorMessage] = useState(null); + const [canSubmit, setCanSubmit] = useState(false); + + const handleEventNameChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + const validation = validateEventName(newValue); + + setCanSubmit(newValue.length !== 0); + setErrorMessage(validation.errorMessage); + + if (validation.isValid) { + setEventName(newValue); + } else { + event.target.value = eventName; + } + }; + + return { + eventName, + errorMessage, + canSubmit, + handleEventNameChange, + }; +}; + +export default useSetEventNamePage; diff --git a/client/src/hooks/useSetEventPasswordPage.ts b/client/src/hooks/useSetEventPasswordPage.ts new file mode 100644 index 000000000..82ca72fb1 --- /dev/null +++ b/client/src/hooks/useSetEventPasswordPage.ts @@ -0,0 +1,60 @@ +import {useEffect, useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; + +import validateEventPassword from '@utils/validate/validateEventPassword'; + +import {ROUTER_URLS} from '@constants/routerUrls'; +import RULE from '@constants/rule'; + +import usePostEvent from './queries/useRequestPostEvent'; + +const useSetEventPasswordPage = () => { + const [eventName, setEventName] = useState(''); + const [password, setPassword] = useState(''); + const [errorMessage, setErrorMessage] = useState(''); + const [canSubmit, setCanSubmit] = useState(false); + const navigate = useNavigate(); + const location = useLocation(); + const {mutate: postEvent, isPending: isPostEventPending} = usePostEvent(); + + useEffect(() => { + if (!location.state) { + navigate(ROUTER_URLS.main); + } else { + setEventName(location.state.eventName); + } + }, []); + + const submitPassword = async (event: React.FormEvent) => { + event.preventDefault(); + + postEvent( + {eventName, password: parseInt(password)}, + { + onSuccess: data => { + navigate(`${ROUTER_URLS.eventCreateComplete}?${new URLSearchParams({eventId: data.eventId})}`, { + replace: true, + }); + }, + }, + ); + }; + + const handleChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + const validation = validateEventPassword(newValue); + + setCanSubmit(newValue.length === RULE.maxEventPasswordLength); + + if (validation.isValid) { + setPassword(newValue); + setErrorMessage(''); + } else { + event.target.value = password; + setErrorMessage(validation.errorMessage ?? ''); + } + }; + + return {submitPassword, errorMessage, password, handleChange, canSubmit, isPostEventPending}; +}; +export default useSetEventPasswordPage; diff --git a/client/src/hooks/useToast/ToastProvider.tsx b/client/src/hooks/useToast/ToastProvider.tsx new file mode 100644 index 000000000..be0d2ea15 --- /dev/null +++ b/client/src/hooks/useToast/ToastProvider.tsx @@ -0,0 +1,47 @@ +/** @jsxImportSource @emotion/react */ +import {createContext, useEffect, useState} from 'react'; + +import {ToastProps} from '../../components/Toast/Toast.type'; +import Toast from '../../components/Toast/Toast'; + +export const ToastContext = createContext(null); + +const DEFAULT_TIME = 3000; + +interface ToastContextProps { + showToast: (args: ShowToast) => void; +} + +type ShowToast = ToastProps & { + showingTime?: number; + isAlwaysOn?: boolean; +}; + +export const ToastProvider = ({children}: React.PropsWithChildren) => { + const [currentToast, setCurrentToast] = useState(null); + + const showToast = ({showingTime = DEFAULT_TIME, isAlwaysOn = false, ...toastProps}: ShowToast) => { + setCurrentToast({showingTime, isAlwaysOn, ...toastProps}); + }; + + const closeToast = () => { + setCurrentToast(null); + }; + + useEffect(() => { + if (currentToast && !currentToast.isAlwaysOn) { + const timer = setTimeout(() => setCurrentToast(null), currentToast.showingTime); + + return () => clearTimeout(timer); + } + + return; + }, [currentToast]); + + return ( + + {currentToast && } + {children} + + ); +}; diff --git a/client/src/hooks/useToast/useToast.test.tsx b/client/src/hooks/useToast/useToast.test.tsx new file mode 100644 index 000000000..f790ba98e --- /dev/null +++ b/client/src/hooks/useToast/useToast.test.tsx @@ -0,0 +1,80 @@ +import {render, renderHook, screen, waitFor} from '@testing-library/react'; +import {act} from 'react'; +import {HDesignProvider} from 'haengdong-design'; + +import {ToastProvider} from './ToastProvider'; // 위 코드에 해당하는 ToastProvider 경로 +import {useToast} from './useToast'; + +const TOAST_CONFIG = { + message: 'Test Toast Message', +}; + +// 테스트용 헬퍼 컴포넌트 +const TestComponent = () => { + const {showToast} = useToast(); + + const handleClick = () => { + showToast(TOAST_CONFIG); + }; + + return ; +}; + +const setup = () => + render( + + + + + , + ); + +describe('ToastProvider', () => { + it('토스트를 띄우고 자동으로 사라지게 한다', async () => { + setup(); + + // 토스트를 띄우기 위해 버튼 클릭 + act(() => { + screen.getByText('Show Toast').click(); + }); + + // 토스트 메시지가 나타나는지 확인 + expect(screen.getByText(TOAST_CONFIG.message)).toBeInTheDocument(); + + // 1초 후에 토스트 메시지가 사라지는지 확인 + await waitFor( + () => { + expect(screen.queryByText(TOAST_CONFIG.message)).not.toBeInTheDocument(); + }, + {timeout: 3100}, + ); // 타임아웃을 3100ms로 설정하여 정확히 3초 후 확인 + }); + + it('토스트 닫기 버튼을 눌렀을 때 사라진다', async () => { + setup(); + + // 토스트를 띄우기 위해 버튼 클릭 + act(() => { + screen.getByText('Show Toast').click(); + }); + + // 토스트 메시지가 나타나는지 확인 + expect(screen.getByText(TOAST_CONFIG.message)).toBeInTheDocument(); + + // 토스트의 닫기 버튼을 클릭 + act(() => { + document.getElementById('toast')?.click(); + }); + + // 닫기 버튼을 클릭한 후 토스트가 사라지는지 확인 + await waitFor(() => { + expect(screen.queryByText(TOAST_CONFIG.message)).not.toBeInTheDocument(); + }); + }); + + it('Provider없이 useToast 사용할 경우 에러를 던진다.', () => { + expect(() => { + const _ = renderHook(() => useToast()); + }).toThrow('useToast는 ToastProvider 내에서 사용되어야 합니다.'); + }); +}); diff --git a/client/src/hooks/useToast/useToast.tsx b/client/src/hooks/useToast/useToast.tsx new file mode 100644 index 000000000..189847405 --- /dev/null +++ b/client/src/hooks/useToast/useToast.tsx @@ -0,0 +1,13 @@ +import {useContext} from 'react'; + +import {ToastContext} from './ToastProvider'; + +export const useToast = () => { + const context = useContext(ToastContext); + + if (!context) { + throw new Error('useToast는 ToastProvider 내에서 사용되어야 합니다.'); + } + + return context; +}; diff --git a/client/src/index.tsx b/client/src/index.tsx new file mode 100644 index 000000000..17f98655f --- /dev/null +++ b/client/src/index.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import {RouterProvider} from 'react-router-dom'; +import * as Sentry from '@sentry/react'; + +import router from './router'; + +// async function enableMocking() { +// const {worker} = await import('./mocks/browser'); +// return worker.start(); +// } + +Sentry.init({ + dsn: 'https://81685591a3234c689be8c48959b04c88@o4507739935997952.ingest.us.sentry.io/4507739943272448', + integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()], + // Performance Monitoring + tracesSampleRate: 1.0, // Capture 100% of the transactions + // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled + tracePropagationTargets: ['localhost', /^https:\/\/api\.haengdong\.pro/], + // Session Replay + replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. + replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. +}); + +// MSW 모킹을 사용하려면 아래 주석을 해제하고 save해주세요. +// enableMocking().then(() => { +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +); +// }); diff --git a/client/src/mocks/browser.ts b/client/src/mocks/browser.ts new file mode 100644 index 000000000..dd8d73b6c --- /dev/null +++ b/client/src/mocks/browser.ts @@ -0,0 +1,5 @@ +import {setupWorker} from 'msw/browser'; + +import {handlers} from './handlers'; + +export const worker = setupWorker(...handlers); diff --git a/client/src/mocks/handlers.ts b/client/src/mocks/handlers.ts new file mode 100644 index 000000000..4189b2d66 --- /dev/null +++ b/client/src/mocks/handlers.ts @@ -0,0 +1,15 @@ +import {authHandler} from './handlers/authHandlers'; +import {eventHandler} from './handlers/eventHandlers'; +import {reportHandlers} from './handlers/reportHandlers'; +import {stepListHandler} from './handlers/stepListHandler'; +import {testHandler} from './handlers/testHandlers'; +import {memberReportInActionHandler} from './handlers/memberReportInActionHandlers'; + +export const handlers = [ + ...authHandler, + ...eventHandler, + ...testHandler, + ...stepListHandler, + ...reportHandlers, + ...memberReportInActionHandler, +]; diff --git a/client/src/mocks/handlers/authHandlers.ts b/client/src/mocks/handlers/authHandlers.ts new file mode 100644 index 000000000..31532eea7 --- /dev/null +++ b/client/src/mocks/handlers/authHandlers.ts @@ -0,0 +1,104 @@ +import {HttpResponse, http} from 'msw'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import {PASSWORD_LENGTH} from '@constants/password'; + +import { + EXPIRED_TOKEN_FOR_TEST, + FORBIDDEN_TOKEN_FOR_TEST, + VALID_PASSWORD_FOR_TEST, + VALID_TOKEN_FOR_TEST, +} from '@mocks/validValueForTest'; + +type PostLoginParams = { + eventId: string; +}; + +type PostLoginRequestBody = { + password: string; +}; + +export const authHandler = [ + http.post(`${TEMP_PREFIX}/:eventId/auth`, ({cookies}) => { + const token = cookies['eventToken']; + + if (token === VALID_TOKEN_FOR_TEST) { + return new HttpResponse(null, { + status: 200, + }); + } else if (token === EXPIRED_TOKEN_FOR_TEST) { + return HttpResponse.json( + { + errorCode: 'TOKEN_EXPIRED', + message: '만료된 토큰입니다.', + }, + {status: 401}, + ); + } else if (token === FORBIDDEN_TOKEN_FOR_TEST) { + return HttpResponse.json( + { + errorCode: 'FORBIDDEN', + message: '접근할 수 없는 행사입니다.', + }, + {status: 401}, + ); + } else if (token === undefined) { + return HttpResponse.json( + { + errorCode: 'TOKEN_NOT_FOUND', + message: '토큰이 존재하지 않습니다.', + }, + {status: 401}, + ); + } else { + return HttpResponse.json( + { + errorCode: 'TOKEN_INVALID', + message: '유효하지 않은 토큰입니다.', + }, + {status: 401}, + ); + } + }), + + // TODO: (@weadie) any를 사용한 이유는.. any가 있는 위치가 이 handler함수의 responseBody타입인데, 아래처럼 return하는 것에 대한 예시가 공문에 없습니다. 함수를 까면 되겠지만 시간이 아깝고 알아낸다고 해서 이 responseBody 타입은 사실 중요한게 아니기 때문에 any로 대체하였습니다. + http.post( + `${TEMP_PREFIX}/:eventId/login`, + async ({request}) => { + const {password} = await request.json(); + + if (password === String(VALID_PASSWORD_FOR_TEST)) { + return new HttpResponse(null, { + headers: { + 'Set-Cookie': 'eventToken=abc-123', + }, + }); + } else if (password.length < PASSWORD_LENGTH) { + return HttpResponse.json( + { + errorCode: 'EVENT_PASSWORD_FORMAT_INVALID', + message: `비밀번호는 ${PASSWORD_LENGTH}자리 숫자만 가능합니다.`, + }, + {status: 401}, + ); + } else if (password === undefined) { + return HttpResponse.json( + { + errorCode: 'REQUEST_EMPTY', + message: '비밀번호는 공백일 수 없습니다.', + }, + {status: 401}, + ); + } else { + return HttpResponse.json( + { + errorCode: 'PASSWORD_INVALID', + message: '비밀번호가 일치하지 않습니다.', + }, + {status: 401}, + ); + } + }, + ), +]; diff --git a/client/src/mocks/handlers/eventHandlers.ts b/client/src/mocks/handlers/eventHandlers.ts new file mode 100644 index 000000000..351993e16 --- /dev/null +++ b/client/src/mocks/handlers/eventHandlers.ts @@ -0,0 +1,55 @@ +import {HttpResponse, http} from 'msw'; + +import {RequestPostNewEvent, ResponsePostNewEvent} from '@apis/request/event'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import {PASSWORD_LENGTH} from '@constants/password'; + +import {VALID_EVENT_NAME_LENGTH_IN_SERVER} from '@mocks/serverConstants'; + +type ErrorResponseBody = { + errorCode: string; + message: string; +}; + +export const eventHandler = [ + http.post( + `${TEMP_PREFIX}`, + async ({request}) => { + const {eventName, password} = await request.json(); + + if (String(password).length < PASSWORD_LENGTH) { + return HttpResponse.json( + { + errorCode: 'EVENT_PASSWORD_FORMAT_INVALID', + message: '비밀번호는 4자리 숫자만 가능합니다.', + }, + {status: 401}, + ); + } else if ( + eventName.length < VALID_EVENT_NAME_LENGTH_IN_SERVER.min || + eventName.length > VALID_EVENT_NAME_LENGTH_IN_SERVER.max + ) { + return HttpResponse.json( + { + errorCode: 'EVENT_NAME_LENGTH_INVALID', + message: `행사 이름은 2자 이상 30자 이하만 입력 가능합니다. 입력한 이름 길이 : ${eventName.length}`, + }, + {status: 401}, + ); + } else { + return HttpResponse.json( + { + eventId: 'eventId', + }, + { + headers: { + 'Set-Cookie': 'eventToken=abc-123', + }, + }, + ); + } + }, + ), +]; diff --git a/client/src/mocks/handlers/memberReportInActionHandlers.ts b/client/src/mocks/handlers/memberReportInActionHandlers.ts new file mode 100644 index 000000000..45de357f1 --- /dev/null +++ b/client/src/mocks/handlers/memberReportInActionHandlers.ts @@ -0,0 +1,49 @@ +import {http, HttpResponse} from 'msw'; + +import {MemberReport} from 'types/serviceType'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import memberReportInActionJson from '../memberReportListInAction.json'; + +let memberReportInActionMockData = memberReportInActionJson as MemberReport[]; + +type MemberReportListRequestParams = { + eventId: string; + actionId: string; +}; +type MemberReportListBody = {members: MemberReport[]}; + +export const memberReportInActionHandler = [ + http.get< + MemberReportListRequestParams, + MemberReportListBody, + any, + `${typeof TEMP_PREFIX}/:eventId/bill-actions/:actionId/fixed` + >(`${TEMP_PREFIX}/:eventId/bill-actions/:actionId/fixed`, ({params}) => { + const {actionId} = params; + + if (Number(actionId) === 123) { + return HttpResponse.json({ + members: memberReportInActionMockData, + }); + } + + return HttpResponse.json({ + members: memberReportInActionMockData.slice(0, 2), + }); + }), + + http.put( + `${TEMP_PREFIX}/:eventId/bill-actions/:actionId/fixed`, + async ({request}) => { + const {members} = await request.json(); + + memberReportInActionMockData = members; + + return HttpResponse.json({ + status: 200, + }); + }, + ), +]; diff --git a/client/src/mocks/handlers/reportHandlers.ts b/client/src/mocks/handlers/reportHandlers.ts new file mode 100644 index 000000000..6b256d7d3 --- /dev/null +++ b/client/src/mocks/handlers/reportHandlers.ts @@ -0,0 +1,13 @@ +import {HttpResponse, http} from 'msw'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import reportListJson from '../reportList.json'; + +export const reportHandlers = [ + http.get(`${TEMP_PREFIX}/:eventId/actions/reports`, () => { + return HttpResponse.json({ + reports: reportListJson, + }); + }), +]; diff --git a/client/src/mocks/handlers/stepListHandler.ts b/client/src/mocks/handlers/stepListHandler.ts new file mode 100644 index 000000000..d79b7b0b4 --- /dev/null +++ b/client/src/mocks/handlers/stepListHandler.ts @@ -0,0 +1,113 @@ +import {HttpResponse, http} from 'msw'; + +import {Bill, MemberType, StepList} from 'types/serviceType'; + +import {TEMP_PREFIX} from '@apis/tempPrefix'; + +import stepListJson from '../stepList.json'; + +type StepListResponseBody = { + step: StepList; +}; + +type PostMemberListRequestBody = { + members: string[]; + status: MemberType; +}; + +type PostBillListRequestBody = { + actions: Bill[]; +}; + +let stepListMockData = stepListJson; + +export const stepListHandler = [ + http.get( + `${TEMP_PREFIX}/:eventId/actions`, + () => { + return HttpResponse.json({ + steps: stepListMockData, + }); + }, + ), + + http.get(`${TEMP_PREFIX}/:eventId/members`, () => { + return HttpResponse.json({ + memberNames: stepListMockData + .filter(({type}) => type !== 'BILL') + .map(({actions}) => actions.map(({name}) => name)) + .flat(), + }); + }), + + http.delete<{actionId: string}>(`${TEMP_PREFIX}/:eventId/member-actions/:actionId`, ({params}) => { + const {actionId} = params; + + if (parseInt(actionId) === 999) { + return HttpResponse.json( + { + errorCode: 'MEMBER_ACTION_STATUS_INVALID', + message: 'actionId는 999일 수 없습니다.(고의로 만든 에러임)', + }, + {status: 401}, + ); + } else { + return HttpResponse.json({ + status: 200, + }); + } + }), + + http.post( + `${TEMP_PREFIX}/:eventId/member-actions`, + async ({request}) => { + const {members, status} = await request.json(); + stepListMockData = [ + ...stepListJson, + { + type: status, + stepName: '영차영차', + members: status === 'IN' ? members : [], + actions: members.map(name => ({ + actionId: 999, + name, + price: 0, + sequence: 999, + isFixed: false, + })), + }, + ]; + + return HttpResponse.json({ + status: 200, + }); + }, + ), + + http.post( + `${TEMP_PREFIX}/:eventId/bill-actions`, + async ({request}) => { + const {actions} = await request.json(); + + stepListMockData = [ + ...stepListJson, + { + type: 'BILL', + stepName: '밥스카이', + members: [], + actions: actions.map(({title, price}) => ({ + actionId: 999, + name: title, + price, + sequence: 999, + isFixed: false, + })), + }, + ]; + + return HttpResponse.json({ + status: 200, + }); + }, + ), +]; diff --git a/client/src/mocks/handlers/testHandlers.ts b/client/src/mocks/handlers/testHandlers.ts new file mode 100644 index 000000000..fda96a1f0 --- /dev/null +++ b/client/src/mocks/handlers/testHandlers.ts @@ -0,0 +1,23 @@ +import {HttpResponse, http} from 'msw'; + +export const testHandler = [ + http.post(`/throw-handle-error`, () => { + return HttpResponse.json( + { + errorCode: 'TOKEN_NOT_FOUND', + message: '핸들링되는 테스트 에러입니다.', + }, + {status: 400}, + ); + }), + + http.post(`/throw-unhandle-error`, () => { + return HttpResponse.json( + { + errorCode: 'strange error', + message: '핸들링이 안되는 테스트 에러입니다.', + }, + {status: 500}, + ); + }), +]; diff --git a/client/src/mocks/invalidMemberStepList.json b/client/src/mocks/invalidMemberStepList.json new file mode 100644 index 000000000..33ca77e4c --- /dev/null +++ b/client/src/mocks/invalidMemberStepList.json @@ -0,0 +1,100 @@ +[ + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 999, + "name": "망쵸", + "price": null, + "sequence": 1, + "isFixed": false + }, + { + "actionId": 2, + "name": "백호", + "price": null, + "sequence": 2, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "1차", + "members": ["망쵸", "백호"], + "actions": [ + { + "actionId": 3, + "name": "감자탕", + "price": 10000, + "sequence": 3, + "isFixed": false + }, + { + "actionId": 4, + "name": "인생네컷", + "price": 10000, + "sequence": 4, + "isFixed": false + } + ] + }, + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 5, + "name": "소하", + "price": null, + "sequence": 5, + "isFixed": false + }, + { + "actionId": 6, + "name": "웨디", + "price": null, + "sequence": 6, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "2차", + "members": ["소하", "웨디"], + "actions": [ + { + "actionId": 9, + "name": "노래방", + "price": 20000, + "sequence": 10, + "isFixed": false + } + ] + }, + { + "type": "OUT", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 7, + "name": "망쵸", + "price": null, + "sequence": 7, + "isFixed": false + }, + { + "actionId": 8, + "name": "백호", + "price": null, + "sequence": 8, + "isFixed": false + } + ] + } +] diff --git a/client/src/mocks/memberActionStepList.json b/client/src/mocks/memberActionStepList.json new file mode 100644 index 000000000..734db4a75 --- /dev/null +++ b/client/src/mocks/memberActionStepList.json @@ -0,0 +1,23 @@ +[ + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 1, + "name": "망쵸", + "price": null, + "sequence": 1, + "isFixed": false + }, + { + "actionId": 2, + "name": "백호", + "price": null, + "sequence": 2, + "isFixed": false + } + ] + } +] diff --git a/client/src/mocks/memberReportListInAction.json b/client/src/mocks/memberReportListInAction.json new file mode 100644 index 000000000..2e24670cb --- /dev/null +++ b/client/src/mocks/memberReportListInAction.json @@ -0,0 +1,6 @@ +[ + {"name": "망쵸", "price": 25000, "isFixed": false}, + {"name": "이상", "price": 25000, "isFixed": false}, + {"name": "소하", "price": 25000, "isFixed": false}, + {"name": "쿠키", "price": 25000, "isFixed": false} +] diff --git a/client/src/mocks/memberReportSearchList.json b/client/src/mocks/memberReportSearchList.json new file mode 100644 index 000000000..dfcb684b1 --- /dev/null +++ b/client/src/mocks/memberReportSearchList.json @@ -0,0 +1,10 @@ +[ + {"name": "망쵸", "price": 1033200}, + {"name": "이상", "price": 10100}, + {"name": "소하", "price": 10000}, + {"name": "쿠키", "price": 100012}, + {"name": "토다리", "price": 1001230}, + {"name": "감자", "price": 1012300}, + {"name": "백호", "price": 10300}, + {"name": "웨디", "price": 1000} +] diff --git a/client/src/mocks/reportList.json b/client/src/mocks/reportList.json new file mode 100644 index 000000000..a663eb9fd --- /dev/null +++ b/client/src/mocks/reportList.json @@ -0,0 +1,18 @@ +[ + { + "name": "소하", + "price": 40000 + }, + { + "name": "감자", + "price": 20000 + }, + { + "name": "쿠키", + "price": 40000 + }, + { + "name": "토다리", + "price": 0 + } +] diff --git a/client/src/mocks/server.ts b/client/src/mocks/server.ts new file mode 100644 index 000000000..157a298e0 --- /dev/null +++ b/client/src/mocks/server.ts @@ -0,0 +1,5 @@ +import {setupServer} from 'msw/node'; + +import {handlers} from './handlers'; + +export const server = setupServer(...handlers); diff --git a/client/src/mocks/serverConstants.ts b/client/src/mocks/serverConstants.ts new file mode 100644 index 000000000..1063a2f75 --- /dev/null +++ b/client/src/mocks/serverConstants.ts @@ -0,0 +1,4 @@ +export const VALID_EVENT_NAME_LENGTH_IN_SERVER = { + min: 2, + max: 30, +}; diff --git a/client/src/mocks/stepList.json b/client/src/mocks/stepList.json new file mode 100644 index 000000000..355692d58 --- /dev/null +++ b/client/src/mocks/stepList.json @@ -0,0 +1,100 @@ +[ + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 1, + "name": "망쵸", + "price": null, + "sequence": 1, + "isFixed": false + }, + { + "actionId": 2, + "name": "백호", + "price": null, + "sequence": 2, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "1차", + "members": ["망쵸", "백호"], + "actions": [ + { + "actionId": 3, + "name": "감자탕", + "price": 10000, + "sequence": 3, + "isFixed": false + }, + { + "actionId": 4, + "name": "인생네컷", + "price": 10000, + "sequence": 4, + "isFixed": false + } + ] + }, + { + "type": "IN", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 5, + "name": "소하", + "price": null, + "sequence": 5, + "isFixed": false + }, + { + "actionId": 6, + "name": "웨디", + "price": null, + "sequence": 6, + "isFixed": false + } + ] + }, + { + "type": "BILL", + "stepName": "2차", + "members": ["소하", "웨디"], + "actions": [ + { + "actionId": 9, + "name": "노래방", + "price": 20000, + "sequence": 10, + "isFixed": false + } + ] + }, + { + "type": "OUT", + "stepName": null, + "members": [], + "actions": [ + { + "actionId": 7, + "name": "망쵸", + "price": null, + "sequence": 7, + "isFixed": false + }, + { + "actionId": 8, + "name": "백호", + "price": null, + "sequence": 8, + "isFixed": false + } + ] + } +] diff --git a/client/src/mocks/svg.ts b/client/src/mocks/svg.ts new file mode 100644 index 000000000..ffe2050a0 --- /dev/null +++ b/client/src/mocks/svg.ts @@ -0,0 +1,2 @@ +export default 'SvgrURL'; +export const ReactComponent = 'div'; diff --git a/client/src/mocks/validValueForTest.ts b/client/src/mocks/validValueForTest.ts new file mode 100644 index 000000000..31f587134 --- /dev/null +++ b/client/src/mocks/validValueForTest.ts @@ -0,0 +1,4 @@ +export const VALID_PASSWORD_FOR_TEST = 1111; +export const VALID_TOKEN_FOR_TEST = 'valid-token'; +export const FORBIDDEN_TOKEN_FOR_TEST = 'forbidden-token'; +export const EXPIRED_TOKEN_FOR_TEST = 'expired-token'; diff --git a/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx new file mode 100644 index 000000000..066165d6a --- /dev/null +++ b/client/src/pages/CreateEventPage/CompleteCreateEventPage.tsx @@ -0,0 +1,29 @@ +import {useLocation, useNavigate} from 'react-router-dom'; +import {FixedButton, MainLayout, Title, TopNav} from 'haengdong-design'; + +import {RunningDog} from '@components/Common/Logo'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const CompleteCreateEventPage = () => { + const navigate = useNavigate(); + const location = useLocation(); + + const params = new URLSearchParams(location.search); + const eventId = params.get('eventId'); + + return ( + + + + <RunningDog /> + <FixedButton onClick={() => navigate(`${ROUTER_URLS.event}/${eventId}/admin`)}>관리 페이지로 이동</FixedButton> + </MainLayout> + ); +}; + +export default CompleteCreateEventPage; diff --git a/client/src/pages/CreateEventPage/SetEventNamePage.tsx b/client/src/pages/CreateEventPage/SetEventNamePage.tsx new file mode 100644 index 000000000..ad68327d2 --- /dev/null +++ b/client/src/pages/CreateEventPage/SetEventNamePage.tsx @@ -0,0 +1,42 @@ +import {useNavigate} from 'react-router-dom'; +import {FixedButton, MainLayout, LabelInput, Title, TopNav, Back} from 'haengdong-design'; +import {css} from '@emotion/react'; + +import useSetEventNamePage from '@hooks/useSetEventNamePage'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const SetEventNamePage = () => { + const navigate = useNavigate(); + const {eventName, errorMessage, canSubmit, handleEventNameChange} = useSetEventNamePage(); + + const submitEventName = (event: React.FormEvent<HTMLFormElement>) => { + event.preventDefault(); + + navigate(ROUTER_URLS.eventCreatePassword, {state: {eventName}}); + }; + + return ( + <MainLayout backgroundColor="white"> + <TopNav> + <Back /> + </TopNav> + <Title title="행사 이름 입력" description="시작할 행사 이름을 입력해 주세요." /> + <form onSubmit={submitEventName} css={css({padding: '0 1rem'})}> + <LabelInput + labelText="행사 이름" + errorText={errorMessage ?? ''} + value={eventName} + type="text" + placeholder="행사 이름" + onChange={handleEventNameChange} + isError={!!errorMessage} + autoFocus + ></LabelInput> + <FixedButton disabled={!canSubmit}>다음</FixedButton> + </form> + </MainLayout> + ); +}; + +export default SetEventNamePage; diff --git a/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx b/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx new file mode 100644 index 000000000..14fcdd75b --- /dev/null +++ b/client/src/pages/CreateEventPage/SetEventPasswordPage.tsx @@ -0,0 +1,41 @@ +import {FixedButton, MainLayout, LabelInput, Title, TopNav, Back} from 'haengdong-design'; + +import useSetEventPasswordPage from '@hooks/useSetEventPasswordPage'; + +import RULE from '@constants/rule'; +import {PASSWORD_LENGTH} from '@constants/password'; + +const SetEventPasswordPage = () => { + const {submitPassword, errorMessage, password, handleChange, canSubmit, isPostEventPending} = + useSetEventPasswordPage(); + + return ( + <MainLayout backgroundColor="white"> + <TopNav> + <Back /> + </TopNav> + <Title + title="행사 비밀번호 설정" + description={`행사 관리에 필요한 ${PASSWORD_LENGTH} 자리의 숫자 비밀번호를 입력해 주세요.`} + /> + <form onSubmit={submitPassword} style={{padding: '0 1rem'}}> + <LabelInput + labelText="비밀번호" + errorText={errorMessage} + value={password} + type="text" + maxLength={RULE.maxEventPasswordLength} + placeholder="비밀번호" + onChange={handleChange} + isError={!!errorMessage} + autoFocus + /> + <FixedButton variants={isPostEventPending ? 'loading' : 'primary'} disabled={!canSubmit}> + 행동 개시! + </FixedButton> + </form> + </MainLayout> + ); +}; + +export default SetEventPasswordPage; diff --git a/client/src/pages/CreateEventPage/index.ts b/client/src/pages/CreateEventPage/index.ts new file mode 100644 index 000000000..6d3d6c808 --- /dev/null +++ b/client/src/pages/CreateEventPage/index.ts @@ -0,0 +1,3 @@ +export {default as SetEventNamePage} from './SetEventNamePage'; +export {default as SetEventPasswordPage} from './SetEventPasswordPage'; +export {default as CompleteCreateEventPage} from './CompleteCreateEventPage'; diff --git a/client/src/pages/ErrorPage/ErrorPage.tsx b/client/src/pages/ErrorPage/ErrorPage.tsx new file mode 100644 index 000000000..31ef8c81f --- /dev/null +++ b/client/src/pages/ErrorPage/ErrorPage.tsx @@ -0,0 +1,14 @@ +import {MainLayout, Title} from 'haengdong-design'; + +const ErrorPage = () => { + return ( + <MainLayout> + <Title + title="알 수 없는 오류입니다." + description="오류가 난 상황에 대해 haengdongdj@gmail.com 로 연락주시면 소정의 상품을 드립니다." + /> + </MainLayout> + ); +}; + +export default ErrorPage; diff --git a/client/src/pages/EventPage/AdminPage/AdminPage.style.ts b/client/src/pages/EventPage/AdminPage/AdminPage.style.ts new file mode 100644 index 000000000..cf6bb0042 --- /dev/null +++ b/client/src/pages/EventPage/AdminPage/AdminPage.style.ts @@ -0,0 +1,23 @@ +import {css} from '@emotion/react'; + +export const receiptStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + gap: '1rem', + paddingBottom: '2rem', + }); + +export const titleAndListButtonContainerStyle = () => + css({ + display: 'flex', + flexDirection: 'column', + }); + +export const buttonGroupStyle = () => + css({ + display: 'flex', + width: '100%', + padding: '0 0.5rem', + gap: '0.5rem', + }); diff --git a/client/src/pages/EventPage/AdminPage/AdminPage.tsx b/client/src/pages/EventPage/AdminPage/AdminPage.tsx new file mode 100644 index 000000000..79deeac7a --- /dev/null +++ b/client/src/pages/EventPage/AdminPage/AdminPage.tsx @@ -0,0 +1,90 @@ +import {useEffect, useState} from 'react'; +import {Title, FixedButton, ListButton, Button} from 'haengdong-design'; +import {useOutletContext} from 'react-router-dom'; + +import StepList from '@components/StepList/StepList'; +import {ModalBasedOnMemberCount, SetAllMemberListModal} from '@components/Modal/index'; +import useRequestGetAllMemberList from '@hooks/queries/useRequestGetAllMemberList'; +import useRequestPostAuthenticate from '@hooks/queries/useRequestPostAuthentication'; + +import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore'; + +import {EventPageContextProps} from '../EventPageLayout'; + +import {receiptStyle, titleAndListButtonContainerStyle, buttonGroupStyle} from './AdminPage.style'; + +const AdminPage = () => { + const [isOpenFixedButtonBottomSheet, setIsOpenFixedButtonBottomSheet] = useState(false); + const [isOpenAllMemberListButton, setIsOpenAllMemberListButton] = useState(false); + const [isAddEditableItem, setIsAddEditableItem] = useState(false); + + const {eventName} = useOutletContext<EventPageContextProps>(); + const {data: allMemberListData} = useRequestGetAllMemberList(); + const allMemberList = allMemberListData?.memberNames ?? []; + + const {totalExpenseAmount} = useTotalExpenseAmountStore(); + + const {mutate: postAuthentication} = useRequestPostAuthenticate(); + + useEffect(() => { + postAuthentication(); + }, [postAuthentication]); + + const handleOpenAllMemberListButton = () => { + setIsOpenFixedButtonBottomSheet(prev => !prev); + setIsOpenAllMemberListButton(prev => !prev); + }; + + const getTitleDescriptionByInitialMemberSetting = () => { + return allMemberList.length > 0 + ? `지출 내역 및 인원 변동을 추가해 주세요. + 인원 변동을 기준으로 몇 차인지 나뉘어져요.` + : '“시작 인원 추가” 버튼을 눌러 행사의 시작부터 참여하는 사람들의 이름을 입력해 주세요.'; + }; + + return ( + <> + <div css={titleAndListButtonContainerStyle}> + <Title title={eventName} description={getTitleDescriptionByInitialMemberSetting()} price={totalExpenseAmount} /> + {allMemberList.length !== 0 && ( + <ListButton + prefix="전체 참여자" + suffix={`${allMemberList.length}명`} + onClick={handleOpenAllMemberListButton} + /> + )} + </div> + <section css={receiptStyle}> + <StepList isAddEditableItem={isAddEditableItem} setIsAddEditableItem={setIsAddEditableItem} /> + {allMemberList.length === 0 ? ( + <FixedButton children={'시작인원 추가하기'} onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)} /> + ) : ( + <div css={buttonGroupStyle}> + <Button + size="medium" + variants="tertiary" + style={{width: '100%'}} + onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)} + > + 인원 변동 추가 + </Button> + <Button size="medium" onClick={() => setIsAddEditableItem(true)} style={{width: '100%'}}> + 지출 내역 추가 + </Button> + </div> + )} + {isOpenFixedButtonBottomSheet && ( + <ModalBasedOnMemberCount + allMemberList={allMemberList} + setIsOpenBottomSheet={setIsOpenFixedButtonBottomSheet} + isOpenBottomSheet={isOpenFixedButtonBottomSheet} + isOpenAllMemberListButton={isOpenAllMemberListButton} + setIsOpenAllMemberListButton={setIsOpenAllMemberListButton} + /> + )} + </section> + </> + ); +}; + +export default AdminPage; diff --git a/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx b/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx new file mode 100644 index 000000000..741dca3eb --- /dev/null +++ b/client/src/pages/EventPage/AdminPage/EventLoginPage.tsx @@ -0,0 +1,35 @@ +import {FixedButton, LabelInput, Title} from 'haengdong-design'; + +import useEventLogin from '@hooks/useEventLogin'; + +import RULE from '@constants/rule'; +import {PASSWORD_LENGTH} from '@constants/password'; + +const EventLoginPage = () => { + const {password, errorMessage, handleChange, canSubmit, submitPassword} = useEventLogin(); + + return ( + <> + <Title + title="행사 비밀번호 입력" + description={`관리를 위해선 비밀번호가 필요해요. 행사 생성 시 설정한 ${PASSWORD_LENGTH} 자리의 숫자 비밀번호를 입력해 주세요.`} + /> + <form onSubmit={submitPassword} style={{padding: '0 1rem'}}> + <LabelInput + labelText="비밀번호" + errorText={errorMessage} + value={password} + type="secret" + maxLength={RULE.maxEventPasswordLength} + placeholder="비밀번호" + onChange={e => handleChange(e)} + isError={!!errorMessage} + autoFocus + ></LabelInput> + <FixedButton disabled={!canSubmit}>관리 페이지로</FixedButton> + </form> + </> + ); +}; + +export default EventLoginPage; diff --git a/client/src/pages/EventPage/AdminPage/index.ts b/client/src/pages/EventPage/AdminPage/index.ts new file mode 100644 index 000000000..b80c0bb2f --- /dev/null +++ b/client/src/pages/EventPage/AdminPage/index.ts @@ -0,0 +1 @@ +export {default as AdminPage} from './AdminPage'; diff --git a/client/src/pages/EventPage/EventPageLayout.tsx b/client/src/pages/EventPage/EventPageLayout.tsx new file mode 100644 index 000000000..6f00c23f1 --- /dev/null +++ b/client/src/pages/EventPage/EventPageLayout.tsx @@ -0,0 +1,65 @@ +import {MainLayout, TopNav, Switch, Button} from 'haengdong-design'; +import {Outlet, useMatch} from 'react-router-dom'; +import CopyToClipboard from 'react-copy-to-clipboard'; + +import {useToast} from '@hooks/useToast/useToast'; +import useRequestGetEventName from '@hooks/queries/useRequestGetEventName'; + +import useNavSwitch from '@hooks/useNavSwitch'; + +import getEventIdByUrl from '@utils/getEventIdByUrl'; +import getEventPageUrlByEnvironment from '@utils/getEventPageUrlByEnvironment'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +export type EventPageContextProps = { + isAdmin: boolean; + eventName: string; +}; + +const EventPageLayout = () => { + const {nav, paths, onChange} = useNavSwitch(); + const {data} = useRequestGetEventName(); + const eventName = data?.eventName ?? ''; + const eventId = getEventIdByUrl(); + + const isAdmin = useMatch(ROUTER_URLS.eventManage) !== null; + const isLoginPage = useMatch(ROUTER_URLS.eventLogin) !== null; + + const outletContext: EventPageContextProps = { + isAdmin, + eventName, + }; + + const {showToast} = useToast(); + const url = getEventPageUrlByEnvironment(eventId, 'home'); + + return ( + <MainLayout backgroundColor="gray"> + <TopNav> + <Switch value={nav} values={paths} onChange={onChange} /> + {!isLoginPage && ( + <CopyToClipboard + text={`[행동대장]\n"${eventName}"에 대한 정산을 시작할게요:)\n아래 링크에 접속해서 정산 내역을 확인해 주세요!\n${url}`} + onCopy={() => + showToast({ + showingTime: 3000, + message: '링크가 복사되었어요 :) \n참여자들에게 링크를 공유해 주세요!', + type: 'confirm', + position: 'bottom', + bottom: '8rem', + }) + } + > + <Button size="small" variants="secondary"> + 정산 초대하기 + </Button> + </CopyToClipboard> + )} + </TopNav> + <Outlet context={outletContext} /> + </MainLayout> + ); +}; + +export default EventPageLayout; diff --git a/client/src/pages/EventPage/HomePage/HomePage.tsx b/client/src/pages/EventPage/HomePage/HomePage.tsx new file mode 100644 index 000000000..72fc77cb9 --- /dev/null +++ b/client/src/pages/EventPage/HomePage/HomePage.tsx @@ -0,0 +1,26 @@ +import {Tab, Tabs, Title} from 'haengdong-design'; +import {useOutletContext} from 'react-router-dom'; + +import MemberReportList from '@components/MemberReportList/MemberReportList'; +import StepList from '@components/StepList/StepList'; + +import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore'; + +import {EventPageContextProps} from '../EventPageLayout'; + +const HomePage = () => { + const {eventName} = useOutletContext<EventPageContextProps>(); + const {totalExpenseAmount} = useTotalExpenseAmountStore(); + + return ( + <div style={{paddingBottom: '2rem'}}> + <Title title={eventName} price={totalExpenseAmount} /> + <Tabs tabsContainerStyle={{gap: '1rem'}}> + <Tab label="전체 지출 내역" content={<StepList />} /> + <Tab label="참여자 별 내역" content={<MemberReportList />} /> + </Tabs> + </div> + ); +}; + +export default HomePage; diff --git a/client/src/pages/EventPage/HomePage/index.ts b/client/src/pages/EventPage/HomePage/index.ts new file mode 100644 index 000000000..aa0bf2b3f --- /dev/null +++ b/client/src/pages/EventPage/HomePage/index.ts @@ -0,0 +1 @@ +export {default as HomePage} from './HomePage'; diff --git a/client/src/pages/EventPage/index.ts b/client/src/pages/EventPage/index.ts new file mode 100644 index 000000000..5b5c314c7 --- /dev/null +++ b/client/src/pages/EventPage/index.ts @@ -0,0 +1 @@ +export {default as EventPage} from './EventPageLayout'; diff --git a/client/src/pages/MainPage/MainPage.tsx b/client/src/pages/MainPage/MainPage.tsx new file mode 100644 index 000000000..d3a1cd079 --- /dev/null +++ b/client/src/pages/MainPage/MainPage.tsx @@ -0,0 +1,23 @@ +import {MainLayout} from 'haengdong-design'; + +import Nav from './Nav/Nav'; +import MainSection from './Section/MainSection'; +import DescriptionSection from './Section/DescriptionSection'; +import AddBillSection from './Section/AddBillSection'; +import AddMemberSection from './Section/AddMemberSection'; +import MemberReportSection from './Section/MemberReportSection'; + +const MainPage = () => { + return ( + <MainLayout> + <Nav /> + <MainSection /> + <DescriptionSection /> + <AddBillSection /> + <AddMemberSection /> + <MemberReportSection /> + </MainLayout> + ); +}; + +export default MainPage; diff --git a/client/src/pages/MainPage/Nav/Nav.style.ts b/client/src/pages/MainPage/Nav/Nav.style.ts new file mode 100644 index 000000000..58cf1cb86 --- /dev/null +++ b/client/src/pages/MainPage/Nav/Nav.style.ts @@ -0,0 +1,22 @@ +import {css} from '@emotion/react'; + +export const navStyle = css({ + position: 'fixed', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '1rem', + + top: '0', + width: '100%', + maxWidth: '768px', + zIndex: '20', + height: '4rem', + backgroundColor: 'white', +}); + +export const logoStyle = css({ + display: 'flex', + gap: '0.5rem', + alignItems: 'center', +}); diff --git a/client/src/pages/MainPage/Nav/Nav.tsx b/client/src/pages/MainPage/Nav/Nav.tsx new file mode 100644 index 000000000..ec4d745c9 --- /dev/null +++ b/client/src/pages/MainPage/Nav/Nav.tsx @@ -0,0 +1,27 @@ +import {Button, Flex, Text} from 'haengdong-design'; +import {useNavigate} from 'react-router-dom'; + +import Heundeut from '@assets/image/heundeut.svg'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +import {logoStyle, navStyle} from './Nav.style'; + +const Nav = () => { + const navigate = useNavigate(); + return ( + <header css={navStyle}> + <Flex gap="0.5rem"> + <Heundeut /> + <div css={logoStyle}> + <Text size="subTitle">행동대장</Text> + </div> + </Flex> + <Button size="medium" variants="tertiary" onClick={() => navigate(ROUTER_URLS.eventCreateName)}> + 정산 시작하기 + </Button> + </header> + ); +}; + +export default Nav; diff --git a/client/src/pages/MainPage/Section/AddBillSection.tsx b/client/src/pages/MainPage/Section/AddBillSection.tsx new file mode 100644 index 000000000..ecf7dd90d --- /dev/null +++ b/client/src/pages/MainPage/Section/AddBillSection.tsx @@ -0,0 +1,31 @@ +import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; + +import AddBillMockup from '@assets/image/addBillMockup.svg'; + +const AddBillSection = () => { + return ( + <div + css={css({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + padding: '3rem', + gap: '2rem', + width: '100%', + backgroundColor: 'white', + })} + > + <div css={css({display: 'flex', flexDirection: 'column', gap: '1rem'})}> + <Text size="subTitle">지출내역을 쉽게 추가하세요</Text> + <Text size="body" textColor="gray"> + {`나중에 한번에 기록할 수도 있지만, + 실시간으로 기록해 놓을 수 있어요`} + </Text> + </div> + <AddBillMockup /> + </div> + ); +}; + +export default AddBillSection; diff --git a/client/src/pages/MainPage/Section/AddMemberSection.tsx b/client/src/pages/MainPage/Section/AddMemberSection.tsx new file mode 100644 index 000000000..ae6e7d1fc --- /dev/null +++ b/client/src/pages/MainPage/Section/AddMemberSection.tsx @@ -0,0 +1,33 @@ +import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; +import {useTheme} from 'haengdong-design/dist/theme/HDesignProvider'; + +import AddMemberMockup from '@assets/image/addMemberMockup.svg'; + +const AddMemberSection = () => { + const {theme} = useTheme(); + return ( + <div + css={css({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + padding: '3rem', + gap: '2rem', + width: '100%', + backgroundColor: theme.colors.lightGrayContainer, + })} + > + <div css={css({display: 'flex', flexDirection: 'column', gap: '1rem'})}> + <Text size="subTitle">인원 변동은 신경쓰지 마세요</Text> + <Text size="body" textColor="gray"> + {`누가 나가고 들어왔는지만 기록하세요 + 행동대장이 알아서 차수를 나눠줘요`} + </Text> + </div> + <AddMemberMockup /> + </div> + ); +}; + +export default AddMemberSection; diff --git a/client/src/pages/MainPage/Section/DescriptionSection.tsx b/client/src/pages/MainPage/Section/DescriptionSection.tsx new file mode 100644 index 000000000..193cfe465 --- /dev/null +++ b/client/src/pages/MainPage/Section/DescriptionSection.tsx @@ -0,0 +1,33 @@ +import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; +import {useTheme} from 'haengdong-design/dist/theme/HDesignProvider'; + +const DescriptionSection = () => { + const {theme} = useTheme(); + + return ( + <div + css={css({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + width: '100%', + gap: '1.5rem', + padding: '3rem 1.5rem', + backgroundColor: theme.colors.lightGrayContainer, + })} + > + <Text style={{textAlign: 'center'}} size="subTitle">{`행동대장들을 위해 + 행동대장을 준비했어요 + `}</Text> + <Text style={{textAlign: 'center'}} size="subTitle" textColor="gray">{`주환이가 먼저 집에 가도 + 소연이가 늦게 도착해도 + 건상이가 술을 마시지 않아도 + `}</Text> + <Text style={{textAlign: 'center'}} size="subTitle">{`간편하게 정산할 수 있어요`}</Text> + </div> + ); +}; + +export default DescriptionSection; diff --git a/client/src/pages/MainPage/Section/MainSection.tsx b/client/src/pages/MainPage/Section/MainSection.tsx new file mode 100644 index 000000000..4bbeb7340 --- /dev/null +++ b/client/src/pages/MainPage/Section/MainSection.tsx @@ -0,0 +1,93 @@ +import {css, keyframes} from '@emotion/react'; +import {Button, Text} from 'haengdong-design'; +import {useNavigate} from 'react-router-dom'; + +import {StandingDog} from '@components/Common/Logo'; +import ChevronDown from '@assets/image/chevronDownLarge.svg'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +const MainSection = () => { + const navigate = useNavigate(); + return ( + <div + css={css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + height: '100vh', + width: '100%', + backgroundColor: 'white', + })} + > + <div + css={css({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + gap: '2rem', + padding: '1.5rem', + height: '100vh', + width: '100%', + })} + > + <div css={animateWithDelay(0)}> + <StandingDog /> + </div> + <Text css={animateWithDelay(1)} style={{textAlign: 'center'}} size="title">{`행동대장을 통해 + 간편하게 정산하세요 + `}</Text> + <Button css={animateWithDelay(2)} size="large" onClick={() => navigate(ROUTER_URLS.eventCreateName)}> + 정산 시작하기 + </Button> + </div> + <div + css={css({ + position: 'absolute', + bottom: '2rem', + left: '50%', + animation: `${bounce} 2s infinite ease-in-out`, + })} + > + <ChevronDown /> + </div> + </div> + ); +}; + +const fadeIn = keyframes` + from { + opacity: 0; + } + to { + opacity: 1; + } +`; + +const slideIn = keyframes` + from { + transform: translateY(1rem); + } + to { + transform: translateY(0); + } +`; + +const bounce = keyframes` + 0%, 100% { + transform: translate(-50%, 0); + } + 50% { + transform: translate(-50%, -1rem); + } +`; + +const animateWithDelay = (delay: number) => css` + opacity: 0; + animation: + ${fadeIn} 1s ease-in-out ${delay}s forwards, + ${slideIn} 1s ease-in-out ${delay}s forwards; +`; + +export default MainSection; diff --git a/client/src/pages/MainPage/Section/MemberReportSection.tsx b/client/src/pages/MainPage/Section/MemberReportSection.tsx new file mode 100644 index 000000000..69871e1c9 --- /dev/null +++ b/client/src/pages/MainPage/Section/MemberReportSection.tsx @@ -0,0 +1,31 @@ +import {css} from '@emotion/react'; +import {Text} from 'haengdong-design'; + +import MemberReportMockup from '@assets/image/memberReportMockup.svg'; + +const MemberReportSection = () => { + return ( + <div + css={css({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + padding: '3rem', + gap: '2rem', + width: '100%', + backgroundColor: 'white', + })} + > + <div css={css({display: 'flex', flexDirection: 'column', gap: '1rem'})}> + <Text size="subTitle">친구에게 링크를 공유하세요</Text> + <Text size="body" textColor="gray"> + {`지출내역과 인원변동을 통해 + 금액은 자동으로 계산돼요`} + </Text> + </div> + <MemberReportMockup /> + </div> + ); +}; + +export default MemberReportSection; diff --git a/client/src/pages/MainPage/index.ts b/client/src/pages/MainPage/index.ts new file mode 100644 index 000000000..017fff307 --- /dev/null +++ b/client/src/pages/MainPage/index.ts @@ -0,0 +1 @@ +export {default as MainPage} from './MainPage'; diff --git a/client/src/router.tsx b/client/src/router.tsx new file mode 100644 index 000000000..51162c775 --- /dev/null +++ b/client/src/router.tsx @@ -0,0 +1,58 @@ +import {createBrowserRouter} from 'react-router-dom'; + +import {AdminPage} from '@pages/EventPage/AdminPage'; +import {HomePage} from '@pages/EventPage/HomePage'; +import ErrorPage from '@pages/ErrorPage/ErrorPage'; +import EventLoginPage from '@pages/EventPage/AdminPage/EventLoginPage'; + +import {CompleteCreateEventPage, SetEventNamePage, SetEventPasswordPage} from '@pages/CreateEventPage'; +import {MainPage} from '@pages/MainPage'; +import {EventPage} from '@pages/EventPage'; + +import {ROUTER_URLS} from '@constants/routerUrls'; + +import App from './App'; + +const router = createBrowserRouter([ + { + path: '', + element: <App />, + children: [ + { + index: true, + path: ROUTER_URLS.main, + element: <MainPage />, + }, + { + path: ROUTER_URLS.eventCreateName, + element: <SetEventNamePage />, + }, + { + path: ROUTER_URLS.eventCreatePassword, + element: <SetEventPasswordPage />, + }, + { + path: ROUTER_URLS.eventCreateComplete, + element: <CompleteCreateEventPage />, + }, + { + path: ROUTER_URLS.event, + element: <EventPage />, + children: [ + {path: ROUTER_URLS.eventManage, element: <AdminPage />}, + {path: ROUTER_URLS.home, element: <HomePage />}, + { + path: ROUTER_URLS.eventLogin, + element: <EventLoginPage />, + }, + ], + }, + { + path: '*', + element: <ErrorPage />, + }, + ], + }, +]); + +export default router; diff --git a/client/src/store/appErrorStore.ts b/client/src/store/appErrorStore.ts new file mode 100644 index 000000000..ca350d4cb --- /dev/null +++ b/client/src/store/appErrorStore.ts @@ -0,0 +1,14 @@ +import {create} from 'zustand'; + +type State = { + appError: Error | null; +}; + +type Action = { + updateAppError: (appError: State['appError']) => void; +}; + +export const useAppErrorStore = create<State & Action>(set => ({ + appError: null, + updateAppError: appError => set(() => ({appError})), +})); diff --git a/client/src/store/stepListStore.ts b/client/src/store/stepListStore.ts new file mode 100644 index 000000000..07f3b107f --- /dev/null +++ b/client/src/store/stepListStore.ts @@ -0,0 +1,16 @@ +import {create} from 'zustand'; + +import {ConvertedAction} from 'types/serviceType'; + +type State = { + stepList: ConvertedAction[]; +}; + +type Action = { + updateStepList: (stepList: State['stepList']) => void; +}; + +export const useStepListStore = create<State & Action>(set => ({ + stepList: [], + updateStepList: stepList => set(() => ({stepList})), +})); diff --git a/client/src/store/totalExpenseAmountStore.ts b/client/src/store/totalExpenseAmountStore.ts new file mode 100644 index 000000000..e9ebcf52a --- /dev/null +++ b/client/src/store/totalExpenseAmountStore.ts @@ -0,0 +1,18 @@ +import {create} from 'zustand'; + +import {BillStep, MemberStep} from 'types/serviceType'; + +import {getTotalExpenseAmount} from '@utils/caculateExpense'; + +type State = { + totalExpenseAmount: number; +}; + +type Action = { + updateTotalExpenseAmount: (stepList: (MemberStep | BillStep)[]) => void; +}; + +export const useTotalExpenseAmountStore = create<State & Action>(set => ({ + totalExpenseAmount: 0, + updateTotalExpenseAmount: stepList => set({totalExpenseAmount: getTotalExpenseAmount(stepList)}), +})); diff --git a/client/src/types/fetchErrorType.ts b/client/src/types/fetchErrorType.ts new file mode 100644 index 000000000..19fe8ee6f --- /dev/null +++ b/client/src/types/fetchErrorType.ts @@ -0,0 +1,11 @@ +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; + +import {Method} from '@apis/fetcher'; + +export type FetchErrorType = Error & { + requestBody: string; + status: number; + endpoint: string; + errorInfo: ErrorInfo; + method: Method; +}; diff --git a/client/src/types/serviceType.ts b/client/src/types/serviceType.ts new file mode 100644 index 000000000..0467995f1 --- /dev/null +++ b/client/src/types/serviceType.ts @@ -0,0 +1,80 @@ +export type MemberType = 'IN' | 'OUT'; + +export type InOutType = '늦참' | '탈주'; + +export type MemberReport = { + name: string; + price: number; +}; + +export type MemberReportInAction = MemberReport & { + isFixed: boolean; +}; + +export type Bill = { + title: string; + price: number; +}; + +type StepBase = { + members: string[]; +}; + +export type MemberStep = StepBase & { + type: MemberType; + stepName: null; + actions: MemberAction[]; +}; + +export type BillStep = StepBase & { + type: 'BILL'; + stepName: string; + actions: BillAction[]; +}; + +// (@weadie) 준 데이터 형식에서 steps를 빼내 flat하게 사용중. 일관성있게 하는게 좋긴 하나 사용시 번거로움이 있을 거라고 판단. +export type StepList = { + steps: (MemberStep | BillStep)[]; +}; + +export type Action = { + actionId: number; + name: string; + price: number | null; + sequence: number; + isFixed: boolean; +}; + +export type BillAction = Omit<Action, 'price'> & { + price: number; +}; + +export type MemberAction = Omit<Action, 'price'> & { + price: null; +}; + +export type Member = { + name: string; + status: MemberType; +}; + +export type ActionType = 'IN' | 'OUT' | 'BILL'; + +// export type StepList = { +// actions: Action[]; +// }; + +export type ConvertedAction = { + actionId: number; + name: string; + price: string | null; + sequence: number; + type: ActionType; +}; + +export type InputPair = Omit<Bill, 'price'> & { + price: string; + index: number; +}; + +export type BillInputType = 'title' | 'price'; diff --git a/client/src/utils/caculateExpense.ts b/client/src/utils/caculateExpense.ts new file mode 100644 index 000000000..8b41af8c3 --- /dev/null +++ b/client/src/utils/caculateExpense.ts @@ -0,0 +1,14 @@ +import {BillAction, BillStep, MemberStep} from 'types/serviceType'; + +export const calculateStepExpense = (actions: BillAction[]) => { + return actions.reduce((sum, {price}) => sum + price, 0); +}; + +export const getTotalExpenseAmount = (stepList: (MemberStep | BillStep)[]) => { + return stepList.reduce((sum, {type, actions}) => { + if (type === 'BILL') { + return sum + calculateStepExpense(actions); + } + return sum; + }, 0); +}; diff --git a/client/src/utils/captureError.ts b/client/src/utils/captureError.ts new file mode 100644 index 000000000..67a30ac99 --- /dev/null +++ b/client/src/utils/captureError.ts @@ -0,0 +1,49 @@ +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; + +import sendLogToSentry from './sendLogToSentry'; + +export const captureError = async (error: Error, errorInfo: ErrorInfo) => { + // prod 환경에서만 Sentry capture 실행 + if (process.env.NODE_ENV !== 'production') return; + + switch (errorInfo?.errorCode) { + case 'INTERNAL_SERVER_ERROR': + sendLogToSentry({error, errorInfo, level: 'fatal'}); + break; + + case 'FORBIDDEN': + sendLogToSentry({error, errorInfo}); + + break; + + case 'TOKEN_INVALID': + sendLogToSentry({error, errorInfo}); + + break; + + case 'TOKEN_EXPIRED': + sendLogToSentry({error, errorInfo}); + + break; + + case 'TOKEN_NOT_FOUND': + sendLogToSentry({error, errorInfo}); + + break; + + // 비밀 번호를 까먹는 사람이 얼마나 많은 지 추측하기 위함 + case 'PASSWORD_INVALID': + sendLogToSentry({error, errorInfo, level: 'debug'}); + + break; + + // 1천만원 이상 입력하는 사람이 얼마나 많은 지 추측하기 위함 + case 'BILL_ACTION_PRICE_INVALID': + sendLogToSentry({error, errorInfo, level: 'debug'}); + break; + + default: + sendLogToSentry({error, errorInfo, level: 'fatal'}); + break; + } +}; diff --git a/client/src/utils/getEventIdByUrl.ts b/client/src/utils/getEventIdByUrl.ts new file mode 100644 index 000000000..1cdb16c8f --- /dev/null +++ b/client/src/utils/getEventIdByUrl.ts @@ -0,0 +1,13 @@ +import REGEXP from '@constants/regExp'; + +const extractEventIdFromUrl = (url: string) => { + const regex = REGEXP.eventUrl; + const match = url.match(regex); + return match ? match[1] : null; +}; + +const getEventIdByUrl = () => { + return extractEventIdFromUrl(window.location.pathname) ?? ''; +}; + +export default getEventIdByUrl; diff --git a/client/src/utils/getEventPageUrlByEnvironment.ts b/client/src/utils/getEventPageUrlByEnvironment.ts new file mode 100644 index 000000000..bcfce54e9 --- /dev/null +++ b/client/src/utils/getEventPageUrlByEnvironment.ts @@ -0,0 +1,11 @@ +import {ROUTER_URLS} from '@constants/routerUrls'; + +type EventPageTab = 'home' | 'admin'; + +const getEventPageUrlByEnvironment = (eventId: string, tab: EventPageTab) => { + const isDevelopment = process.env.NODE_ENV === 'development'; + + return `https://${isDevelopment ? 'dev.' : ''}haengdong.pro${ROUTER_URLS.event}/${eventId}/${tab}`; +}; + +export default getEventPageUrlByEnvironment; diff --git a/client/src/utils/groupActions.ts b/client/src/utils/groupActions.ts new file mode 100644 index 000000000..a6347167d --- /dev/null +++ b/client/src/utils/groupActions.ts @@ -0,0 +1,27 @@ +import {BillStep, ConvertedAction, MemberStep} from 'types/serviceType'; + +import stepListToAction from './stepListToActions'; + +const groupActions = (stepList: (BillStep | MemberStep)[]) => { + const actions = stepListToAction(stepList); + const groupedActions: ConvertedAction[][] = []; + + let group: ConvertedAction[] = []; + + actions.forEach((action, index) => { + if (group.length === 0 || group[group.length - 1].type === action.type) { + group.push(action); + } else { + groupedActions.push(group); + group = []; + } + + if (index === actions.length - 1) { + groupedActions.push(group); + } + }); + + return groupedActions; +}; + +export default groupActions; diff --git a/client/src/utils/isArraysEqual.ts b/client/src/utils/isArraysEqual.ts new file mode 100644 index 000000000..df73a8552 --- /dev/null +++ b/client/src/utils/isArraysEqual.ts @@ -0,0 +1,16 @@ +const isArraysEqual = <T>(arr1: T[], arr2: T[]) => { + if (arr1.length !== arr2.length) return false; + + // 배열을 정렬한 후 비교 + const sortedArr1 = [...arr1].sort(); + const sortedArr2 = [...arr2].sort(); + + // 값은 모두 같으나 순서를 변경했을 시, false를 반환한다. + for (let i = 0; i < sortedArr1.length; i++) { + if (sortedArr1[i] !== sortedArr2[i]) return false; + } + + return true; +}; + +export default isArraysEqual; diff --git a/client/src/utils/objectToQueryString.ts b/client/src/utils/objectToQueryString.ts new file mode 100644 index 000000000..cc40fb076 --- /dev/null +++ b/client/src/utils/objectToQueryString.ts @@ -0,0 +1,9 @@ +import {ObjectQueryParams} from '@apis/fetcher'; + +const objectToQueryString = (params: ObjectQueryParams): string => { + return Object.entries(params) + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); +}; + +export default objectToQueryString; diff --git a/client/src/utils/sendLogToSentry.ts b/client/src/utils/sendLogToSentry.ts new file mode 100644 index 000000000..22d736b6c --- /dev/null +++ b/client/src/utils/sendLogToSentry.ts @@ -0,0 +1,66 @@ +import * as Sentry from '@sentry/react'; + +import {ErrorInfo} from '@components/AppErrorBoundary/ErrorCatcher'; + +import {UNKNOWN_ERROR} from '@constants/errorMessage'; + +import FetchError from '../errors/FetchError'; + +/** + * level은 아래와 같은 용도에 맞게 지정해줍니다. + * + * fatal: 앱이 종료될 수 있는 치명적인 오류 + * error: 특정 기능 실패로 앱 종료까지는 아닌 오류 + * warning: 잠재적으로 문제가 될 수 있는 오류. 현재는 심각하지 않은 오류 + * info: 시스템의 정상적인 동작을 나타냄. 중요한 이벤트나 상태 변화 기록용 + * debug: 디버깅 목적으로 사용됨 + * log: 일반적인 로그 메세지 + */ + +type SentryLevel = 'fatal' | 'error' | 'warning' | 'info' | 'debug' | 'log'; +type SendLogToSentry = { + level?: SentryLevel; + error: Error; + errorInfo: ErrorInfo; +}; + +const sendLogToSentry = ({level = 'error', error, errorInfo}: SendLogToSentry) => { + Sentry.withScope(scope => { + const {errorCode, message} = errorInfo; + scope.setLevel(level); + + scope.setTag('environment', process.env.NODE_ENV); + + if (error instanceof FetchError) { + scope.setTags({ + endpoint: error.endpoint, + url: window.location.href, + errorCode, + errorMessage: message, + status: error.status, + // requestBody: JSON.stringify(error.requestBody), + method: error.method, + }); + + Sentry.captureMessage(`${errorCode}`); + } else if (error instanceof Error) { + scope.setTags({ + url: window.location.href, + errorCode, + errorMessage: message, + }); + + Sentry.captureMessage(`${errorCode}`); + } else { + scope.setTags({ + url: window.location.href, + errorCode, + message: UNKNOWN_ERROR, + name: UNKNOWN_ERROR, + }); + Sentry.captureMessage(`${errorCode}`); + } + }); +}; + +export default sendLogToSentry; diff --git a/client/src/utils/stepListToActions.ts b/client/src/utils/stepListToActions.ts new file mode 100644 index 000000000..5fe1bb3a7 --- /dev/null +++ b/client/src/utils/stepListToActions.ts @@ -0,0 +1,23 @@ +import {BillStep, ConvertedAction, MemberStep} from 'types/serviceType'; + +const stepListToAction = (stepList: (BillStep | MemberStep)[]) => { + // (@todari) test용이라 임시로 any 사용할게용... + // Action을 사용하려고 하는데 serviceType의 기존 Action이랑 겹쳐서요~~~ + const actions: ConvertedAction[] = []; + + stepList.forEach(step => { + step.actions.forEach(action => { + actions.push({ + actionId: action.actionId, + name: action.name, + price: action.price ? action.price.toLocaleString() : null, + sequence: action.sequence, + type: step.type, + }); + }); + }); + + return actions; +}; + +export default stepListToAction; diff --git a/client/src/utils/validate/type.ts b/client/src/utils/validate/type.ts new file mode 100644 index 000000000..df81f1644 --- /dev/null +++ b/client/src/utils/validate/type.ts @@ -0,0 +1,5 @@ +export interface ValidateResult { + isValid: boolean; + errorMessage: string | null; + errorInfo?: Record<string, boolean>; +} diff --git a/client/src/utils/validate/validateEventName.ts b/client/src/utils/validate/validateEventName.ts new file mode 100644 index 000000000..93f4ecef1 --- /dev/null +++ b/client/src/utils/validate/validateEventName.ts @@ -0,0 +1,13 @@ +import {ERROR_MESSAGE} from '@constants/errorMessage'; +import RULE from '@constants/rule'; + +import {ValidateResult} from './type'; + +const validateEventName = (name: string): ValidateResult => { + if (name.length > RULE.maxEventNameLength) { + return {isValid: false, errorMessage: ERROR_MESSAGE.eventName}; + } + return {isValid: true, errorMessage: null}; +}; + +export default validateEventName; diff --git a/client/src/utils/validate/validateEventPassword.ts b/client/src/utils/validate/validateEventPassword.ts new file mode 100644 index 000000000..7075e2f3e --- /dev/null +++ b/client/src/utils/validate/validateEventPassword.ts @@ -0,0 +1,13 @@ +import {ERROR_MESSAGE} from '@constants/errorMessage'; +import REGEXP from '@constants/regExp'; + +import {ValidateResult} from './type'; + +const validateEventPassword = (password: string): ValidateResult => { + if (!REGEXP.eventPassword.test(password)) { + return {isValid: false, errorMessage: ERROR_MESSAGE.eventPasswordType}; + } + return {isValid: true, errorMessage: null}; +}; + +export default validateEventPassword; diff --git a/client/src/utils/validate/validateMemberName.ts b/client/src/utils/validate/validateMemberName.ts new file mode 100644 index 000000000..bb87122a2 --- /dev/null +++ b/client/src/utils/validate/validateMemberName.ts @@ -0,0 +1,34 @@ +import REGEXP from '@constants/regExp'; +import {ERROR_MESSAGE} from '@constants/errorMessage'; +import RULE from '@constants/rule'; + +import {ValidateResult} from './type'; + +const validateMemberName = (name: string): ValidateResult => { + let errorMessage = null; + const validateOnlyString = () => { + if (!REGEXP.memberName.test(name)) return false; + return true; + }; + + const validateLength = () => { + if (name.length > RULE.maxMemberNameLength) return false; + return true; + }; + + const validateEmpty = () => { + if (!name.trim().length) { + errorMessage = ERROR_MESSAGE.preventEmpty; + return false; + } + return true; + }; + + if (validateOnlyString() && validateLength() && validateEmpty()) { + return {isValid: true, errorMessage: null}; + } + + return {isValid: false, errorMessage: errorMessage || ERROR_MESSAGE.memberName}; +}; + +export default validateMemberName; diff --git a/client/src/utils/validate/validateMemberReportInAction.ts b/client/src/utils/validate/validateMemberReportInAction.ts new file mode 100644 index 000000000..b4e6c2a9a --- /dev/null +++ b/client/src/utils/validate/validateMemberReportInAction.ts @@ -0,0 +1,33 @@ +import {ERROR_MESSAGE} from '@constants/errorMessage'; +import RULE from '@constants/rule'; + +import {ValidateResult} from './type'; + +const validateMemberReportInAction = (price: string, totalPrice: number): ValidateResult => { + let errorMessage = null; + const numberTypePrice = Number(price); + + const validateOnlyNaturalNumber = () => { + if (!(Number.isInteger(numberTypePrice) && numberTypePrice >= 0)) return false; + return true; + }; + + const validatePrice = () => { + if (numberTypePrice > RULE.maxPrice) return false; + return true; + }; + + const validateUnderTotalPrice = () => { + if (numberTypePrice > totalPrice) return false; + + return true; + }; + + if (validateOnlyNaturalNumber() && validatePrice() && validateUnderTotalPrice()) { + return {isValid: true, errorMessage: null}; + } + + return {isValid: false, errorMessage: errorMessage || ERROR_MESSAGE.invalidInput}; +}; + +export default validateMemberReportInAction; diff --git a/client/src/utils/validate/validatePurchase.ts b/client/src/utils/validate/validatePurchase.ts new file mode 100644 index 000000000..9915ce8b7 --- /dev/null +++ b/client/src/utils/validate/validatePurchase.ts @@ -0,0 +1,47 @@ +import type {Bill} from 'types/serviceType'; + +import {ERROR_MESSAGE} from '@constants/errorMessage'; +import RULE from '@constants/rule'; +import REGEXP from '@constants/regExp'; + +import {ValidateResult} from './type'; + +const validatePurchase = (inputPair: Bill): ValidateResult => { + const {title, price} = inputPair; + let errorMessage: string | null = null; + + const errorInfo = { + price: false, + title: false, + }; + + const validatePrice = () => { + if (price > RULE.maxPrice) { + errorMessage = ERROR_MESSAGE.purchasePrice; + errorInfo.price = true; + return false; + } + + errorInfo.price = false; + return true; + }; + + const validateTitle = () => { + if (!REGEXP.purchaseTitle.test(title)) { + errorMessage = ERROR_MESSAGE.purchaseTitle; + errorInfo.title = true; + return false; + } + + errorInfo.title = false; + return true; + }; + + if (validatePrice() && validateTitle()) { + return {isValid: true, errorMessage: null}; + } + + return {isValid: false, errorMessage, errorInfo}; +}; + +export default validatePurchase; diff --git a/client/tsconfig.json b/client/tsconfig.json new file mode 100644 index 000000000..84c7c054a --- /dev/null +++ b/client/tsconfig.json @@ -0,0 +1,53 @@ +{ + "compilerOptions": { + "sourceMap": true, + "module": "ES2020", + "target": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "useDefineForClassFields": true, + "removeComments": true, + "skipLibCheck": true, + + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + "jsx": "react-jsx", + "strict": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + "types": ["jest", "@testing-library/jest-dom", "node", "cypress"], + "esModuleInterop": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + "jsxImportSource": "@emotion/react", + + "baseUrl": "./src", + "paths": { + "@apis/*": ["apis/*"], + "@assets/*": ["assets/*"], + "@components/*": ["components/*"], + "@constants/*": ["constants/*"], + "@store/*": ["store/*"], + "@hooks/*": ["hooks/*"], + "@mocks/*": ["mocks/*"], + "@pages/*": ["pages/*"], + "@utils/*": ["utils/*"], + "@errors/*": ["errors/*"] + }, + "outDir": "./dist" + }, + "node": true, + "include": ["src", "jest.config.ts", "jest.setup.ts", "cypress/**/*.ts"] +} diff --git a/client/webpack.common.mjs b/client/webpack.common.mjs new file mode 100644 index 000000000..160baf0ca --- /dev/null +++ b/client/webpack.common.mjs @@ -0,0 +1,60 @@ +import path from 'path'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import {ModifySourcePlugin, ConcatOperation} from 'modify-source-webpack-plugin'; +import {fileURLToPath} from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default { + entry: './src/index.tsx', + resolve: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + alias: { + '@apis': path.resolve(__dirname, 'src/apis/'), + '@assets': path.resolve(__dirname, 'src/assets/'), + '@components': path.resolve(__dirname, 'src/components/'), + '@constants': path.resolve(__dirname, 'src/constants/'), + '@hooks': path.resolve(__dirname, 'src/hooks/'), + '@store': path.resolve(__dirname, 'src/store/'), + '@mocks': path.resolve(__dirname, 'src/mocks/'), + '@pages': path.resolve(__dirname, 'src/pages/'), + '@utils': path.resolve(__dirname, 'src/utils/'), + '@errors': path.resolve(__dirname, 'src/errors/'), + }, + }, + module: { + rules: [ + { + test: /\.tsx?$/, + loader: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /\.svg$/, + use: [ + { + loader: '@svgr/webpack', + }, + ], + }, + ], + }, + plugins: [ + new HtmlWebpackPlugin({ + template: './index.html', + hash: true, + favicon: './favicon.ico', + }), + new ForkTsCheckerWebpackPlugin(), + new ModifySourcePlugin({ + rules: [ + { + test: /\.tsx$/i, + operations: [new ConcatOperation('start', '/** @jsxImportSource @emotion/react */\n\n')], + }, + ], + }), + ], +}; diff --git a/client/webpack.dev.mjs b/client/webpack.dev.mjs new file mode 100644 index 000000000..5ad42ed45 --- /dev/null +++ b/client/webpack.dev.mjs @@ -0,0 +1,33 @@ +import path from 'path'; +import {merge} from 'webpack-merge'; +import Dotenv from 'dotenv-webpack'; +import common from './webpack.common.mjs'; +import {fileURLToPath} from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default merge(common, { + mode: 'development', + output: { + filename: '[name].js', + chunkFilename: '[id].chunk.js', + path: path.resolve(__dirname, 'dist'), + clean: true, + publicPath: '/', + }, + devtool: 'eval-source-map', + devServer: { + port: 3000, + historyApiFallback: true, + hot: true, + client: { + overlay: false, + }, + }, + plugins: [ + new Dotenv({ + path: '.env.dev', + }), + ], +}); diff --git a/client/webpack.prod.mjs b/client/webpack.prod.mjs new file mode 100644 index 000000000..1cf3bc7d1 --- /dev/null +++ b/client/webpack.prod.mjs @@ -0,0 +1,31 @@ +import path from 'path'; +import {merge} from 'webpack-merge'; +import Dotenv from 'dotenv-webpack'; +import common from './webpack.common.mjs'; +import {fileURLToPath} from 'url'; +import {sentryWebpackPlugin} from '@sentry/webpack-plugin'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default merge(common, { + mode: 'production', + output: { + filename: '[name].[hash].js', + chunkFilename: '[id].[hash].chunk.js', + path: path.resolve(__dirname, 'dist'), + clean: true, + publicPath: '/', + }, + devtool: 'source-map', + plugins: [ + new Dotenv({ + path: '.env.prod', + }), + sentryWebpackPlugin({ + authToken: process.env.SENTRY_AUTH_TOKEN, + org: 'wtc-o6', + project: 'javascript-react', + }), + ], +}); diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 000000000..671ee930b --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,244 @@ +# Created by https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij,gradle,macos,windows,linux + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/java,intellij,gradle,macos,windows,linux diff --git a/server/.gitkeep b/server/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 000000000..df2cf44e0 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,9 @@ +FROM openjdk:17-jdk-slim + +WORKDIR /app + +COPY /build/libs/*.jar /app/haengdong-0.0.1-SNAPSHOT.jar + +EXPOSE 8080 +ENTRYPOINT ["java"] +CMD ["-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-Duser.timezone=Asia/Seoul", "-jar", "haengdong-0.0.1-SNAPSHOT.jar"] diff --git a/server/build.gradle b/server/build.gradle new file mode 100644 index 000000000..4229de130 --- /dev/null +++ b/server/build.gradle @@ -0,0 +1,86 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.1' + id 'io.spring.dependency-management' version '1.1.5' + id 'org.asciidoctor.jvm.convert' version '3.3.2' +} + +group = 'server' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } + asciidoctorExt +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + + implementation 'io.jsonwebtoken:jjwt:0.9.1' + implementation 'javax.xml.bind:jaxb-api:2.3.1' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' +} + +ext { + snippetsDir = file('build/generated-snippets') +} + +test { + useJUnitPlatform() + outputs.dir snippetsDir +} + +asciidoctor { + inputs.dir snippetsDir + configurations 'asciidoctorExt' + baseDirFollowsSourceFile() + dependsOn test +} + +tasks.resolveMainClassName { + dependsOn 'copyApiDocuments' +} + +tasks.register('copyApiDocuments', Copy) { + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("build/resources/main/static/docs") +} + +bootJar { + dependsOn copyApiDocuments +} + +jar { + enabled = false +} + +build { + dependsOn copyApiDocuments +} diff --git a/server/docs/24-08-04-erd.sql b/server/docs/24-08-04-erd.sql new file mode 100644 index 000000000..ae2fbc4a5 --- /dev/null +++ b/server/docs/24-08-04-erd.sql @@ -0,0 +1,65 @@ +-- Create tables +CREATE TABLE action +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + PRIMARY KEY (id) +); + +CREATE TABLE bill_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + price BIGINT, + title VARCHAR(30), + PRIMARY KEY (id) +); + +CREATE TABLE event +( + id BIGINT AUTO_INCREMENT, + name VARCHAR(255), + token VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE event_step +( + event_id BIGINT, + id BIGINT AUTO_INCREMENT, + sequence BIGINT, + name VARCHAR(255), + PRIMARY KEY (id) +); + +CREATE TABLE member_action +( + action_id BIGINT UNIQUE, + id BIGINT AUTO_INCREMENT, + member_group_id BIGINT, + member_name VARCHAR(255), + status ENUM('IN', 'OUT'), + PRIMARY KEY (id) +); + +-- Add foreign key constraints +ALTER TABLE action + ADD CONSTRAINT FKgf0qmub9va1xbe44nehny31yw + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE bill_action + ADD CONSTRAINT FK54tx517tp0ry6453olkply4us + FOREIGN KEY (action_id) + REFERENCES action (id); + +ALTER TABLE event_step + ADD CONSTRAINT FKe3rkib91cvl0x5w9wqkshmn81 + FOREIGN KEY (event_id) + REFERENCES event (id); + +ALTER TABLE member_action + ADD CONSTRAINT FK5jna51dn8fs2ir52l4uwn517u + FOREIGN KEY (action_id) + REFERENCES action (id); diff --git a/server/docs/24-08-04-erd.svg b/server/docs/24-08-04-erd.svg new file mode 100644 index 000000000..5a4bac225 --- /dev/null +++ b/server/docs/24-08-04-erd.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than draw.io --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1993px" height="1581px" viewBox="-0.5 -0.5 1993 1581" content="<mxfile host="app.diagrams.net" modified="2024-07-25T04:17:06.208Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" etag="gR5VLfYLO6MRu5dHcV28" version="24.7.3" type="github"> <diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1"> <mxGraphModel dx="2380" dy="2150" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <root> <mxCell id="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" /> <mxCell id="8gZzuRhjrYuwNxX9kY4q-98" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="-442" y="-590" width="1992" height="1580" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-47" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-37" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-66" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=ERone;startFill=0;endArrow=ERzeroToMany;endFill=0;dashed=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-0" target="8gZzuRhjrYuwNxX9kY4q-56" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-0" value="Event" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-1" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-2" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-3" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-137" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-1" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-7" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-8" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-9" value="token" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-138" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-7" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-4" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-0" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-5" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-6" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-139" value="varchar(255)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-4" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-37" value="Event_Step" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="40" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-38" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-39" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-40" value="event_step_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-143" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-38" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-41" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-42" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-43" value="name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-144" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-41" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-44" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-45" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-46" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-145" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-44" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-48" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-37" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-49" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-50" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-146" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-48" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-77" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-67" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-91" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;startArrow=ERone;startFill=0;endArrow=ERone;endFill=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="8gZzuRhjrYuwNxX9kY4q-56" target="8gZzuRhjrYuwNxX9kY4q-81" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-56" value="Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="40" width="280" height="120" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-57" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-58" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-59" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-140" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-57" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-60" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-61" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-62" value="sequence" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-141" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-60" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-63" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-56" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-64" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-65" value="event_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-142" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-63" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-67" value="Bill_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="414" y="240" width="280" height="150" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-68" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-69" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-70" value="bill_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-147" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-68" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-71" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-72" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-73" value="title" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-148" value="varchar(30)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-71" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-78" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-79" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-80" value="price" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-149" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-78" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-74" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-67" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-75" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-76" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-150" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-74" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-81" value="Member_Action" style="shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1"> <mxGeometry x="790" y="40" width="280" height="180" as="geometry"> <mxRectangle x="480" y="530" width="70" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-82" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=1;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="30" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-83" value="PK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;fontStyle=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-84" value="member_action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-151" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;fontStyle=5;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-82" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-85" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="60" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-86" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-87" value="member_name" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-152" value="varchar(20)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-85" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-92" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="90" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-93" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-94" value="status" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-153" value="varchar(10)" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-92" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-95" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="120" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-96" value="" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-97" value="member_group_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-154" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-95" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-88" value="" style="shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;top=0;left=0;right=0;bottom=0;" parent="8gZzuRhjrYuwNxX9kY4q-81" vertex="1"> <mxGeometry y="150" width="280" height="30" as="geometry" /> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-89" value="FK" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;editable=1;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry width="30" height="30" as="geometry"> <mxRectangle width="30" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-90" value="action_id" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="30" width="120" height="30" as="geometry"> <mxRectangle width="120" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> <mxCell id="8gZzuRhjrYuwNxX9kY4q-155" value="bigint" style="shape=partialRectangle;connectable=0;fillColor=none;top=0;left=0;bottom=0;right=0;align=left;spacingLeft=6;overflow=hidden;whiteSpace=wrap;html=1;" parent="8gZzuRhjrYuwNxX9kY4q-88" vertex="1"> <mxGeometry x="150" width="130" height="30" as="geometry"> <mxRectangle width="130" height="30" as="alternateBounds" /> </mxGeometry> </mxCell> </root> </mxGraphModel> </diagram> </mxfile> " resource="https://app.diagrams.net/?src=about#Hkunsanglee%2Fcafekiosk-study%2Fmain%2Fsrc%2Fmain%2Fresources%2Fexample2.svg#%7B%22pageId%22%3A%22C5RBs43oDa-KdzZeNtuy%22%7D"><defs/><g><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-0"><g data-cell-id="WIyWlLk6GJQsqaUBKTNV-1"><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-98"><g><rect x="0" y="0" width="1992" height="1580" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-47"><g><path d="M 622 750 L 622 814.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 626 754 L 618 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="622" cy="818" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 626 830 L 622 822 L 618 830 M 622 822 L 622 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-66"><g><path d="M 762 690 L 840.5 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 766 686 L 766 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><ellipse cx="844" cy="690" rx="3" ry="3" fill="none" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 856 686 L 848 690 L 856 694 M 848 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-0"><g><path d="M 482 660 L 482 630 L 762 630 L 762 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 660 L 482 750 L 762 750 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 660 L 762 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 660 L 512 690 L 512 720 L 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 660 L 632 690 L 632 720 L 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event</div></div></div></foreignObject><text x="622" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-1"><g><path d="M 482 660 M 762 660 M 762 690 L 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-2"><g><rect x="482" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 660 M 512 660 M 512 690 M 482 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-3"><g><rect x="512" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 660 M 632 660 M 632 690 M 512 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-137"><g><rect x="632" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 660 M 762 660 M 762 690 M 632 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-7"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-8"><g><rect x="482" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 690 M 512 690 M 512 720 M 482 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-9"><g><rect x="512" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 690 M 632 690 M 632 720 M 512 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">token</div></div></div></foreignObject><text x="520" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">token</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-138"><g><rect x="632" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 690 M 762 690 M 762 720 M 632 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="640" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-4"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-5"><g><rect x="482" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 720 M 512 720 M 512 750 M 482 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-6"><g><rect x="512" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 720 M 632 720 M 632 750 M 512 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-139"><g><rect x="632" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 720 M 762 720 M 762 750 M 632 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(255)</div></div></div></foreignObject><text x="640" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(255)</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-37"><g><path d="M 482 860 L 482 830 L 762 830 L 762 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 482 860 L 482 980 L 762 980 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 482 860 L 762 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 512 860 L 512 890 L 512 920 L 512 950 L 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 632 860 L 632 890 L 632 920 L 632 950 L 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 622px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Event_Step</div></div></div></foreignObject><text x="622" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Event_Step</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-38"><g><path d="M 482 860 M 762 860 M 762 890 L 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-39"><g><rect x="482" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 860 M 512 860 M 512 890 M 482 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="497" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-40"><g><rect x="512" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 860 M 632 860 M 632 890 M 512 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">event_step_id</div></div></div></foreignObject><text x="520" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">event_step_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-143"><g><rect x="632" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 860 M 762 860 M 762 890 M 632 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-41"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-42"><g><rect x="482" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 890 M 512 890 M 512 920 M 482 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-43"><g><rect x="512" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 890 M 632 890 M 632 920 M 512 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">name</div></div></div></foreignObject><text x="520" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-144"><g><rect x="632" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 890 M 762 890 M 762 920 M 632 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="640" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-44"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-45"><g><rect x="482" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 920 M 512 920 M 512 950 M 482 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-46"><g><rect x="512" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 920 M 632 920 M 632 950 M 512 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="520" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-145"><g><rect x="632" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 920 M 762 920 M 762 950 M 632 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-48"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-49"><g><rect x="482" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 482 950 M 512 950 M 512 980 M 482 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 483px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="497" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-50"><g><rect x="512" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 512 950 M 632 950 M 632 980 M 512 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 520px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="520" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-146"><g><rect x="632" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 632 950 M 762 950 M 762 980 M 632 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="640" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-77"><g><path d="M 996 750 L 996 830" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1000 754 L 992 754" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 992 826 L 1000 826" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-91"><g><path d="M 1136 690 L 1184 690 L 1184 720 L 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 1140 686 L 1140 694" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1228 724 L 1228 716" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-56"><g><path d="M 856 660 L 856 630 L 1136 630 L 1136 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 660 L 856 750 L 1136 750 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 660 L 1136 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 660 L 886 690 L 886 720 L 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 660 L 1006 690 L 1006 720 L 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Action</div></div></div></foreignObject><text x="996" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-57"><g><path d="M 856 660 M 1136 660 M 1136 690 L 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-58"><g><rect x="856" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 660 M 886 660 M 886 690 M 856 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-59"><g><rect x="886" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 660 M 1006 660 M 1006 690 M 886 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-140"><g><rect x="1006" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 660 M 1136 660 M 1136 690 M 1006 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-60"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-61"><g><rect x="856" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 690 M 886 690 M 886 720 M 856 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-62"><g><rect x="886" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 690 M 1006 690 M 1006 720 M 886 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">sequence</div></div></div></foreignObject><text x="894" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">sequence</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-141"><g><rect x="1006" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 690 M 1136 690 M 1136 720 M 1006 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-63"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-64"><g><rect x="856" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 720 M 886 720 M 886 750 M 856 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 735px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-65"><g><rect x="886" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 720 M 1006 720 M 1006 750 M 886 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">event_id</div></div></div></foreignObject><text x="894" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">event_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-142"><g><rect x="1006" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 720 M 1136 720 M 1136 750 M 1006 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-67"><g><path d="M 856 860 L 856 830 L 1136 830 L 1136 860" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 856 860 L 856 980 L 1136 980 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 856 860 L 1136 860" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 886 860 L 886 890 L 886 920 L 886 950 L 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1006 860 L 1006 890 L 1006 920 L 1006 950 L 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 845px; margin-left: 996px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Bill_Action</div></div></div></foreignObject><text x="996" y="849" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Bill_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-68"><g><path d="M 856 860 M 1136 860 M 1136 890 L 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-69"><g><rect x="856" y="860" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 860 M 886 860 M 886 890 M 856 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 875px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="871" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-70"><g><rect x="886" y="860" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 860 M 1006 860 M 1006 890 M 886 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 875px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bill_action_id</div></div></div></foreignObject><text x="894" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bill_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-147"><g><rect x="1006" y="860" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 860 M 1136 860 M 1136 890 M 1006 890" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 875px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="879" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-71"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-72"><g><rect x="856" y="890" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 890 M 886 890 M 886 920 M 856 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-73"><g><rect x="886" y="890" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 890 M 1006 890 M 1006 920 M 886 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 905px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">title</div></div></div></foreignObject><text x="894" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">title</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-148"><g><rect x="1006" y="890" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 890 M 1136 890 M 1136 920 M 1006 920" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 905px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(30)</div></div></div></foreignObject><text x="1014" y="909" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(30)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-78"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-79"><g><rect x="856" y="920" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 920 M 886 920 M 886 950 M 856 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-80"><g><rect x="886" y="920" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 920 M 1006 920 M 1006 950 M 886 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 935px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">price</div></div></div></foreignObject><text x="894" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">price</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-149"><g><rect x="1006" y="920" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 920 M 1136 920 M 1136 950 M 1006 950" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 935px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="939" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-74"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-75"><g><rect x="856" y="950" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 856 950 M 886 950 M 886 980 M 856 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 965px; margin-left: 857px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="871" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-76"><g><rect x="886" y="950" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 886 950 M 1006 950 M 1006 980 M 886 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 965px; margin-left: 894px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="894" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-150"><g><rect x="1006" y="950" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1006 950 M 1136 950 M 1136 980 M 1006 980" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 965px; margin-left: 1014px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1014" y="969" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-81"><g><path d="M 1232 660 L 1232 630 L 1512 630 L 1512 660" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1232 660 L 1232 810 L 1512 810 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1232 660 L 1512 660" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1262 660 L 1262 690 L 1262 720 L 1262 750 L 1262 780 L 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1382 660 L 1382 690 L 1382 720 L 1382 750 L 1382 780 L 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="none"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 645px; margin-left: 1372px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: nowrap;">Member_Action</div></div></div></foreignObject><text x="1372" y="649" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">Member_Action</text></switch></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-82"><g><path d="M 1232 660 M 1512 660 M 1512 690 L 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="none"/></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-83"><g><rect x="1232" y="660" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 660 M 1262 660 M 1262 690 M 1232 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 675px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">PK</div></div></div></foreignObject><text x="1247" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle" font-weight="bold">PK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-84"><g><rect x="1262" y="660" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 660 M 1382 660 M 1382 690 M 1262 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 675px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">member_action_id</div></div></div></foreignObject><text x="1270" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">member_action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-151"><g><rect x="1382" y="660" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 660 M 1512 660 M 1512 690 M 1382 690" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 675px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; text-decoration: underline; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="679" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" font-weight="bold" text-decoration="underline">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-85"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-86"><g><rect x="1232" y="690" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 690 M 1262 690 M 1262 720 M 1232 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-87"><g><rect x="1262" y="690" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 690 M 1382 690 M 1382 720 M 1262 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 705px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_name</div></div></div></foreignObject><text x="1270" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_name</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-152"><g><rect x="1382" y="690" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 690 M 1512 690 M 1512 720 M 1382 720" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 705px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(20)</div></div></div></foreignObject><text x="1390" y="709" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(20)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-92"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-93"><g><rect x="1232" y="720" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 720 M 1262 720 M 1262 750 M 1232 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-94"><g><rect x="1262" y="720" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 720 M 1382 720 M 1382 750 M 1262 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 735px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">status</div></div></div></foreignObject><text x="1270" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">status</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-153"><g><rect x="1382" y="720" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 720 M 1512 720 M 1512 750 M 1382 750" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 735px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">varchar(10)</div></div></div></foreignObject><text x="1390" y="739" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">varchar(10)</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-95"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-96"><g><rect x="1232" y="750" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 750 M 1262 750 M 1262 780 M 1232 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-97"><g><rect x="1262" y="750" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 750 M 1382 750 M 1382 780 M 1262 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 765px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">member_group_id</div></div></div></foreignObject><text x="1270" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">member_group_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-154"><g><rect x="1382" y="750" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 750 M 1512 750 M 1512 780 M 1382 780" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 765px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="769" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-88"><g/><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-89"><g><rect x="1232" y="780" width="30" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1232 780 M 1262 780 M 1262 810 M 1232 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 28px; height: 1px; padding-top: 795px; margin-left: 1233px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">FK</div></div></div></foreignObject><text x="1247" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px" text-anchor="middle">FK</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-90"><g><rect x="1262" y="780" width="120" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1262 780 M 1382 780 M 1382 810 M 1262 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 112px; height: 1px; padding-top: 795px; margin-left: 1270px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">action_id</div></div></div></foreignObject><text x="1270" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">action_id</text></switch></g></g></g><g data-cell-id="8gZzuRhjrYuwNxX9kY4q-155"><g><rect x="1382" y="780" width="130" height="30" fill="none" stroke="none" pointer-events="all"/><path d="M 1382 780 M 1512 780 M 1512 810 M 1382 810" fill="none" stroke="rgb(0, 0, 0)" stroke-linecap="square" stroke-miterlimit="10" pointer-events="all"/></g><g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 122px; height: 1px; padding-top: 795px; margin-left: 1390px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left; max-height: 26px; overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">bigint</div></div></div></foreignObject><text x="1390" y="799" fill="rgb(0, 0, 0)" font-family=""Helvetica"" font-size="12px">bigint</text></switch></g></g></g></g></g></g></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file diff --git a/server/gradle/wrapper/gradle-wrapper.jar b/server/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e6441136f3d4ba8a0da8d277868979cfbc8ad796 GIT binary patch literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 UfUyy3EX0IC28@JalTrWuAK7&_a{vGU literal 0 HcmV?d00001 diff --git a/server/gradle/wrapper/gradle-wrapper.properties b/server/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..a4413138c --- /dev/null +++ b/server/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/server/gradlew b/server/gradlew new file mode 100644 index 000000000..b740cf133 --- /dev/null +++ b/server/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/server/gradlew.bat b/server/gradlew.bat new file mode 100644 index 000000000..25da30dbd --- /dev/null +++ b/server/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/server/settings.gradle b/server/settings.gradle new file mode 100644 index 000000000..dbbee46fb --- /dev/null +++ b/server/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'haengdong' diff --git a/server/src/docs/asciidoc/billAction.adoc b/server/src/docs/asciidoc/billAction.adoc new file mode 100644 index 000000000..dfd7e26db --- /dev/null +++ b/server/src/docs/asciidoc/billAction.adoc @@ -0,0 +1,121 @@ +== 지출 액션 + +=== 지출 액션 생성 + +operation::createBillActions[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"지출 금액은 비어 있으면 안됩니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"지출 내역은 비어 있으면 안됩니다." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"지출 금액은 10,000,000 이하의 자연수여야 합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 지출 액션 수정 + +operation::updateBillAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"지출 내역 제목은 공백일 수 없습니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"지출 금액은 공백일 수 없습니다." + }, + { + "code":"BILL_ACTION_TITLE_INVALID", + "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." + }, + { + "code":"BILL_ACTION_PRICE_INVALID", + "message":"지출 금액은 %,d 이하의 자연수여야 합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"BILL_ACTION_NOT_FOUND", + "message":"존재하지 않는 지출 액션입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 지출 액션 삭제 + +operation::deleteBillAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/billActionDetail.adoc b/server/src/docs/asciidoc/billActionDetail.adoc new file mode 100644 index 000000000..a8f19f21b --- /dev/null +++ b/server/src/docs/asciidoc/billActionDetail.adoc @@ -0,0 +1,93 @@ +== 지출 상세 + +=== 지출 상세 조회 + +operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "존재하지 않는 지출 액션입니다." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "존재하지 않는 참여자 지출입니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- + +=== 지출 상세 수정 + +operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "REQUEST_EMPTY", + "message": "멤버 이름은 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "지출 금액은 공백일 수 없습니다." + }, + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "BILL_ACTION_NOT_FOUND", + "message": "존재하지 않는 지출 액션입니다." + }, + { + "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "message": "존재하지 않는 참여자 지출입니다." + }, + { + "code": "BILL_ACTION_PRICE_NOT_MATCHED", + "message": "지출 총액이 일치하지 않습니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc new file mode 100644 index 000000000..72511b91b --- /dev/null +++ b/server/src/docs/asciidoc/event.adoc @@ -0,0 +1,205 @@ +== 행사 + +=== 행사 생성 + +operation::createEvent[snippets="http-request,request-body,request-fields,response-body,response-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"행사 이름은 공백일 수 없습니다." + }, + { + "code":"EVENT_NAME_LENGTH_INVALID", + "message":"행사 이름은 2자 이상 30자 이하만 입력 가능합니다. 입력한 이름 길이 : 21" + }, + { + "code":"EVENT_NAME_MULTIPLE_BLANK", + "message":"행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : 공백 문자" + }, + { + "code":"EVENT_PASSWORD_INVALID", + "message":"비밀번호는 4자리 숫자만 가능합니다." + } +] +---- + +=== 행사 관리자 로그인 + +operation::eventLogin[snippets="path-parameters,http-request,request-body,request-fields,http-response,response-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"비밀번호는 공백일 수 없습니다." + }, + { + "code":"PASSWORD_INVALID", + "message":"비밀번호가 일치하지 않습니다." + } +] +---- + +=== 행사 정보 조회 + +operation::getEvent[snippets="path-parameters,http-request,response-body,response-fields,http-response"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 전체 참여자 목록 조회 + +operation::findAllEventMember[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 전체 액션 이력 조회 + +operation::findActions[snippets="path-parameters,http-request,http-response,response-fields"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 행사 참여자 이름 변경 + +operation::updateEventMemberName[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + + { + "code":"MEMBER_NAME_CHANGE_DUPLICATE", + "message":"중복된 참여 인원 이름 변경 요청이 존재합니다." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"현재 참여하고 있지 않는 인원이 존재합니다." + }, + { + "code":"REQUEST_EMPTY", + "message":"멤버 이름은 공백일 수 없습니다." + }, + { + "code":"MEMBER_NAME_LENGTH_INVALID", + "message":"멤버 이름은 1자 이상 4자 이하만 입력 가능합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 행사 참여 인원 이름이 존재합니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 행사 참여자 삭제 (특정 참여자의 모든 참여자 액션 삭제) + +operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 행사 어드민 권한 확인 + +operation::authenticateEvent[snippets="http-request,http-response,request-cookies"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "EVENT_NOT_FOUND", + "message": "존재하지 않는 행사입니다." + }, + { + "code": "TOKEN_NOT_FOUND", + "message": "토큰이 존재하지 않습니다." + }, + { + "code": "TOKEN_EXPIRED", + "message": "만료된 토큰입니다." + }, + { + "code": "TOKEN_INVALID", + "message": "유효하지 않은 토큰입니다." + }, + { + "code": "FORBIDDEN", + "message": "접근할 수 없는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc new file mode 100644 index 000000000..8e1bcd2d0 --- /dev/null +++ b/server/src/docs/asciidoc/index.adoc @@ -0,0 +1,15 @@ +ifndef::snippets[] +:snippets: ../../build/generated-snippets +endif::[] += 행동대장 +:source-highlighter: highlightjs :hardbreaks: +:toc: left :doctype: book :icons: font :toc-title: 전체 API 목록 :toclevels: 2 :sectlinks: +:sectnums: +:sectnumlevels: 2 + + +include::{docdir}/event.adoc[] +include::{docdir}/memberBillReport.adoc[] +include::{docdir}/memberAction.adoc[] +include::{docdir}/billAction.adoc[] +include::{docdir}/billActionDetail.adoc[] diff --git a/server/src/docs/asciidoc/memberAction.adoc b/server/src/docs/asciidoc/memberAction.adoc new file mode 100644 index 000000000..897102c8d --- /dev/null +++ b/server/src/docs/asciidoc/memberAction.adoc @@ -0,0 +1,100 @@ +== 참여자 액션 + +=== 참여자 액션 생성 + +operation::createMemberAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"멤버 액션은 공백일 수 없습니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_ACTION_STATUS_INVALID", + "message":"멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: I_N" + }, + { + "code":"MEMBER_ALREADY_EXIST", + "message":"현재 참여하고 있는 인원이 존재합니다." + }, + { + "code":"MEMBER_NOT_EXIST", + "message":"현재 참여하고 있지 않는 인원이 존재합니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 이름이 존재합니다. 입력된 이름: 이상, 이상, 감자, 백호" + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- + +=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 + +operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- + +=== 참여자 액션 삭제 + +operation::deleteMemberAction[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"ACTION_NOT_FOUND", + "message":"존재하지 않는 액션입니다." + }, + { + "code":"MEMBER_ACTION_NOT_FOUND", + "message":"존재하지 않는 멤버 액션입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/memberBillReport.adoc b/server/src/docs/asciidoc/memberBillReport.adoc new file mode 100644 index 000000000..18bd7d3ef --- /dev/null +++ b/server/src/docs/asciidoc/memberBillReport.adoc @@ -0,0 +1,17 @@ +== 정산 + +=== 참여자별 정산 결과 조회 + +operation::getMemberBillReports[snippets="path-parameters,http-request,response-body,response-fields,http-response,http-request"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- diff --git a/server/src/main/java/server/haengdong/HaengdongApplication.java b/server/src/main/java/server/haengdong/HaengdongApplication.java new file mode 100644 index 000000000..4a84c6120 --- /dev/null +++ b/server/src/main/java/server/haengdong/HaengdongApplication.java @@ -0,0 +1,15 @@ +package server.haengdong; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@Slf4j +@SpringBootApplication +public class HaengdongApplication { + + public static void main(String[] args) { + SpringApplication.run(HaengdongApplication.class, args); + } + +} diff --git a/server/src/main/java/server/haengdong/application/ActionService.java b/server/src/main/java/server/haengdong/application/ActionService.java new file mode 100644 index 000000000..bcf5e8b55 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/ActionService.java @@ -0,0 +1,39 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberBillReport; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class ActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + + public List<MemberBillReportAppResponse> getMemberBillReports(String token) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + return memberBillReport.getReports().entrySet().stream() + .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java new file mode 100644 index 000000000..d9352ad53 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/AuthService.java @@ -0,0 +1,41 @@ +package server.haengdong.application; + + +import java.util.Map; +import server.haengdong.domain.TokenProvider; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; + +public class AuthService { + + private static final String TOKEN_NAME = "eventToken"; + private static final String CLAIM_SUB = "sub"; + + private final TokenProvider tokenProvider; + + public AuthService(TokenProvider tokenProvider) { + this.tokenProvider = tokenProvider; + } + + public String createToken(String eventId) { + Map<String, Object> payload = Map.of(CLAIM_SUB, eventId); + + return tokenProvider.createToken(payload); + } + + public String findEventIdByToken(String token) { + validateToken(token); + Map<String, Object> payload = tokenProvider.getPayload(token); + return (String) payload.get(CLAIM_SUB); + } + + private void validateToken(String token) { + if (!tokenProvider.validateToken(token)) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_INVALID); + } + } + + public String getTokenName() { + return TOKEN_NAME; + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java new file mode 100644 index 000000000..55d39aac0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionDetailService.java @@ -0,0 +1,76 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionDetailService { + + private final BillActionRepository billActionRepository; + + public BillActionDetailsAppResponse findBillActionDetails(String token, Long actionId) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + validateToken(token, billAction); + + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); + return BillActionDetailsAppResponse.of(billActionDetails); + } + + @Transactional + public void updateBillActionDetails(String token, Long actionId, BillActionDetailsUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); + + validateToken(token, billAction); + validateTotalPrice(billActionDetailUpdateAppRequests, billAction); + + List<BillActionDetail> billActionDetails = billAction.getBillActionDetails(); + + for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { + BillActionDetail detailToUpdate = billActionDetails.stream() + .filter(detail -> detail.isSameName(updateRequest.name())) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); + + detailToUpdate.updatePrice(updateRequest.price()); + detailToUpdate.updateIsFixed(updateRequest.isFixed()); + } + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + private void validateTotalPrice(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests, + BillAction billAction) { + Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); + if (!billAction.isSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests) { + return billActionDetailUpdateAppRequests.stream() + .map(BillActionDetailUpdateAppRequest::price) + .reduce(0L, Long::sum); + } +} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java new file mode 100644 index 000000000..dae36a2e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -0,0 +1,80 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillActionService { + + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final ActionRepository actionRepository; + private final EventRepository eventRepository; + + @Transactional + public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) { + Event event = getEvent(eventToken); + Action action = createStartAction(event); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + for (BillActionAppRequest request : requests) { + BillAction billAction = request.toBillAction(action, currentMembers); + billActionRepository.save(billAction); + action = action.next(); + } + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + @Transactional + public void updateBillAction(String token, Long actionId, BillActionUpdateAppRequest request) { + BillAction billAction = billActionRepository.findByAction_Id(actionId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); + + validateToken(token, billAction); + + billAction.update(request.title(), request.price()); + } + + private void validateToken(String token, BillAction billAction) { + Event event = billAction.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); + } + } + + @Transactional + public void deleteBillAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + + billActionRepository.deleteByAction_EventAndActionId(event, actionId); + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java new file mode 100644 index 000000000..1aaddd0f9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -0,0 +1,170 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventLoginAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class EventService { + + private final EventRepository eventRepository; + private final EventTokenProvider eventTokenProvider; + private final BillActionRepository billActionRepository; + private final MemberActionRepository memberActionRepository; + private final BillActionDetailRepository billActionDetailRepository; + + + @Transactional + public EventAppResponse saveEvent(EventAppRequest request) { + String token = eventTokenProvider.createToken(); + Event event = request.toEvent(token); + eventRepository.save(event); + + return EventAppResponse.of(event); + } + + public EventDetailAppResponse findEvent(String token) { + Event event = getEvent(token); + + return EventDetailAppResponse.of(event); + } + + public List<ActionAppResponse> findActions(String token) { + Event event = getEvent(token); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event).stream() + .sorted(Comparator.comparing(BillAction::getSequence)).toList(); + List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event).stream() + .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); + + return getActionAppResponses(billActions, memberActions); + } + + private List<ActionAppResponse> getActionAppResponses( + List<BillAction> billActions, + List<MemberAction> memberActions + ) { + int billActionIndex = 0; + int memberActionIndex = 0; + List<ActionAppResponse> actionAppResponses = new ArrayList<>(); + + while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { + BillAction billAction = billActions.get(billActionIndex); + MemberAction memberAction = memberActions.get(memberActionIndex); + if (billAction.getSequence() < memberAction.getSequence()) { + actionAppResponses.add(ActionAppResponse.of(billAction)); + billActionIndex++; + } else { + actionAppResponses.add(ActionAppResponse.of(memberAction)); + memberActionIndex++; + } + } + while (billActionIndex < billActions.size()) { + BillAction billAction = billActions.get(billActionIndex++); + actionAppResponses.add(ActionAppResponse.of(billAction)); + } + while (memberActionIndex < memberActions.size()) { + MemberAction memberAction = memberActions.get(memberActionIndex++); + actionAppResponses.add(ActionAppResponse.of(memberAction)); + } + + return actionAppResponses; + } + + public MembersAppResponse findAllMembers(String token) { + Event event = getEvent(token); + + List<String> memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); + + return new MembersAppResponse(memberNames); + } + + @Transactional + public void updateMember(String token, MemberNamesUpdateAppRequest request) { + Event event = getEvent(token); + List<MemberNameUpdateAppRequest> members = request.members(); + + validateBeforeNames(members, event); + validateAfterNames(members, event); + + members.forEach(member -> updateMemberName(event, member.before(), member.after())); + } + + private void validateBeforeNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> beforeNames = members.stream() + .map(MemberNameUpdateAppRequest::before) + .toList(); + if (beforeNames.size() != Set.copyOf(beforeNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + beforeNames.forEach(beforeName -> validateBeforeMemberNameExist(event, beforeName)); + } + + private void validateBeforeMemberNameExist(Event event, String beforeName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, beforeName); + if (!isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + private void validateAfterNames(List<MemberNameUpdateAppRequest> members, Event event) { + List<String> afterNames = members.stream() + .map(MemberNameUpdateAppRequest::after) + .toList(); + if (afterNames.size() != Set.copyOf(afterNames).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + afterNames.forEach(afterName -> validateAfterMemberNameNotExist(event, afterName)); + } + + private void validateAfterMemberNameNotExist(Event event, String afterName) { + boolean isMemberNameExist = memberActionRepository.existsByAction_EventAndMemberName(event, afterName); + if (isMemberNameExist) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private void updateMemberName(Event event, String beforeName, String afterName) { + memberActionRepository.findAllByAction_EventAndMemberName(event, beforeName) + .forEach(memberAction -> memberAction.updateMemberName(afterName)); + billActionDetailRepository.findAllByBillAction_Action_EventAndMemberName(event, beforeName) + .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); + } + + public void validatePassword(EventLoginAppRequest request) throws HaengdongException { + Event event = getEvent(request.token()); + if (event.isPasswordMismatch(request.password())) { + throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); + } + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java new file mode 100644 index 000000000..c0a171642 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionFactory.java @@ -0,0 +1,62 @@ +package server.haengdong.application; + +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.action.MemberGroupIdProvider; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Component +public class MemberActionFactory { + + private final MemberGroupIdProvider memberGroupIdProvider; + + public List<MemberAction> createMemberActions( + MemberActionsSaveAppRequest request, + CurrentMembers currentMembers, + Action action + ) { + validateMemberNames(request); + validateActions(request, currentMembers); + + Long memberGroupId = memberGroupIdProvider.createGroupId(); + List<MemberAction> createdMemberActions = new ArrayList<>(); + List<MemberActionSaveAppRequest> actions = request.actions(); + for (MemberActionSaveAppRequest appRequest : actions) { + MemberAction memberAction = appRequest.toMemberAction(action, memberGroupId); + createdMemberActions.add(memberAction); + action = action.next(); + } + + return createdMemberActions; + } + + private void validateMemberNames(MemberActionsSaveAppRequest request) { + List<String> memberNames = request.actions().stream() + .map(MemberActionSaveAppRequest::name) + .toList(); + + long uniqueCount = memberNames.stream().distinct().count(); + if (uniqueCount != memberNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private void validateActions(MemberActionsSaveAppRequest request, CurrentMembers currentMembers) { + List<MemberActionSaveAppRequest> actions = request.actions(); + + for (MemberActionSaveAppRequest action : actions) { + MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); + currentMembers.validate(action.name(), memberActionStatus); + } + } +} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java new file mode 100644 index 000000000..245de8cef --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -0,0 +1,100 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberActionService { + + private final MemberActionFactory memberActionFactory; + private final MemberActionRepository memberActionRepository; + private final EventRepository eventRepository; + private final ActionRepository actionRepository; + private final BillActionRepository billActionRepository; + + @Transactional + public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { + Event event = findEvent(token); + + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + Action action = createStartAction(event); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(request, currentMembers, action); + memberActionRepository.saveAll(memberActions); + } + + private Action createStartAction(Event event) { + return actionRepository.findLastByEvent(event) + .map(Action::next) + .orElse(Action.createFirst(event)); + } + + public List<CurrentMemberAppResponse> getCurrentMembers(String token) { + Event event = findEvent(token); + List<MemberAction> findMemberActions = memberActionRepository.findAllByEvent(event); + CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); + + return currentMembers.getMembers() + .stream() + .map(CurrentMemberAppResponse::new) + .toList(); + } + + private Event findEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + @Transactional + public void deleteMember(String token, String memberName) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + + memberActionRepository.deleteAllByEventAndMemberName(event, memberName); + + List<BillAction> billActions = billActionRepository.findByAction_Event(event); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + @Transactional + public void deleteMemberAction(String token, Long actionId) { + Event event = eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + Action action = actionRepository.findByIdAndEvent(actionId, event) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.ACTION_NOT_FOUND)); + MemberAction memberAction = memberActionRepository.findByAction(action) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); + + memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), + memberAction.getSequence()); + + List<BillAction> billActions = billActionRepository.findByEventAndGreaterThanSequence(event, + action.getSequence()); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + private void resetBillAction(Event event, BillAction billAction) { + List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, + billAction.getSequence()); + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + billAction.resetBillActionDetails(currentMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java new file mode 100644 index 000000000..21eb17d4a --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java @@ -0,0 +1,15 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.CurrentMembers; + +public record BillActionAppRequest( + String title, + Long price +) { + + public BillAction toBillAction(Action action, CurrentMembers currentMembers) { + return BillAction.create(action, title, price, currentMembers); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java new file mode 100644 index 000000000..e514aee81 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +public record BillActionDetailUpdateAppRequest( + String name, + Long price, + boolean isFixed +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java new file mode 100644 index 000000000..1fe19798e --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record BillActionDetailsUpdateAppRequest( + List<BillActionDetailUpdateAppRequest> billActionDetailUpdateAppRequests +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java new file mode 100644 index 000000000..a90e3dd42 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record BillActionUpdateAppRequest( + String title, + Long price +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java new file mode 100644 index 000000000..20ec16d88 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -0,0 +1,10 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.event.Event; + +public record EventAppRequest(String name, String password) { + + public Event toEvent(String token) { + return new Event(name, password, token); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java new file mode 100644 index 000000000..947b5ef39 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventLoginAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record EventLoginAppRequest(String token, String password) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java new file mode 100644 index 000000000..f7f8d8fc2 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java @@ -0,0 +1,12 @@ +package server.haengdong.application.request; + +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record MemberActionSaveAppRequest(String name, String status) { + + public MemberAction toMemberAction(Action action, Long memberGroupId) { + return new MemberAction(action, name, MemberActionStatus.of(status), memberGroupId); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java new file mode 100644 index 000000000..650b908df --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberActionsSaveAppRequest(List<MemberActionSaveAppRequest> actions) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java new file mode 100644 index 000000000..d629d3a02 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java @@ -0,0 +1,7 @@ +package server.haengdong.application.request; + +public record MemberNameUpdateAppRequest( + String before, + String after +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java new file mode 100644 index 000000000..cd0c00544 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberNamesUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MemberNamesUpdateAppRequest( + List<MemberNameUpdateAppRequest> members +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java new file mode 100644 index 000000000..0c2c12611 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java @@ -0,0 +1,61 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionStatus; + +public record ActionAppResponse( + Long actionId, + String name, + Long price, + Long sequence, + boolean isFixed, + ActionType actionType +) { + + public ActionAppResponse(Long actionId, String name, Long price, Long sequence, ActionType actionType) { + this(actionId, name, price, sequence, false, actionType); + } + + public static ActionAppResponse of(BillAction billAction) { + return new ActionAppResponse( + billAction.getAction().getId(), + billAction.getTitle(), + billAction.getPrice(), + billAction.getSequence(), + billAction.isFixed(), + ActionAppResponse.ActionType.BILL + ); + } + + public static ActionAppResponse of(MemberAction memberAction) { + MemberActionStatus status = memberAction.getStatus(); + + return new ActionAppResponse( + memberAction.getAction().getId(), + memberAction.getMemberName(), + null, + memberAction.getSequence(), + false, + ActionAppResponse.ActionType.of(status) + ); + } + + public String actionTypeName() { + return actionType.name(); + } + + public enum ActionType { + BILL, + IN, + OUT, + ; + + private static ActionType of(MemberActionStatus memberActionStatus) { + if (MemberActionStatus.IN == memberActionStatus) { + return IN; + } + return OUT; + } + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java new file mode 100644 index 000000000..3efc7ac9d --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailAppResponse( + String name, + Long price, + boolean isFixed +) { + + public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { + return new BillActionDetailAppResponse( + billActionDetail.getMemberName(), + billActionDetail.getPrice(), + billActionDetail.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java new file mode 100644 index 000000000..061f07816 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.domain.action.BillActionDetail; + +public record BillActionDetailsAppResponse(List<BillActionDetailAppResponse> billActionDetailAppResponses) { + + public static BillActionDetailsAppResponse of(List<BillActionDetail> billActionDetails) { + return billActionDetails.stream() + .map(BillActionDetailAppResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsAppResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java new file mode 100644 index 000000000..6c682d3e9 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.action.MemberAction; + +public record CurrentMemberAppResponse(String name) { + + public static CurrentMemberAppResponse of(MemberAction memberAction) { + return new CurrentMemberAppResponse(memberAction.getMemberName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java new file mode 100644 index 000000000..f331d0011 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventAppResponse(String token) { + + public static EventAppResponse of(Event event) { + return new EventAppResponse(event.getToken()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java new file mode 100644 index 000000000..6e38826d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.event.Event; + +public record EventDetailAppResponse(String eventName) { + + public static EventDetailAppResponse of(Event event) { + return new EventDetailAppResponse(event.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java new file mode 100644 index 000000000..21b6cef56 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -0,0 +1,4 @@ +package server.haengdong.application.response; + +public record MemberBillReportAppResponse(String name, Long price) { +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java new file mode 100644 index 000000000..be8378b37 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java @@ -0,0 +1,8 @@ +package server.haengdong.application.response; + +import java.util.List; + +public record MembersAppResponse( + List<String> memberNames +) { +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java new file mode 100644 index 000000000..a0542ed46 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -0,0 +1,51 @@ +package server.haengdong.config; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import server.haengdong.application.AuthService; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; + +@Slf4j +public class AdminInterceptor implements HandlerInterceptor { + + private final AuthService authService; + private final AuthenticationExtractor authenticationExtractor; + + public AdminInterceptor(AuthService authService, AuthenticationExtractor authenticationExtractor) { + this.authService = authService; + this.authenticationExtractor = authenticationExtractor; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String requestURI = request.getRequestURI(); + + if (requestURI.endsWith("/login")) { + return true; // 요청을 계속 진행하도록 허용 + } + + HttpMethod method = HttpMethod.valueOf(request.getMethod()); + if (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) { + return true; + } + + validateToken(request); + + return true; + } + + private void validateToken(HttpServletRequest request) { + String token = authenticationExtractor.extract(request, authService.getTokenName()); + String tokenEventId = authService.findEventIdByToken(token); + String eventId = request.getRequestURI().split("/")[3]; + if (!tokenEventId.equals(eventId)) { + log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventId); + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); + } + } +} diff --git a/server/src/main/java/server/haengdong/config/RequestServletFilter.java b/server/src/main/java/server/haengdong/config/RequestServletFilter.java new file mode 100644 index 000000000..b1afdb6f8 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/RequestServletFilter.java @@ -0,0 +1,23 @@ +package server.haengdong.config; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import org.springframework.stereotype.Component; +import org.springframework.web.util.ContentCachingRequestWrapper; + +@Component +public class RequestServletFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) request); + + chain.doFilter(wrappedRequest, response); + } +} diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java new file mode 100644 index 000000000..d1caa176f --- /dev/null +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -0,0 +1,66 @@ +package server.haengdong.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.AuthService; +import server.haengdong.domain.TokenProvider; +import server.haengdong.infrastructure.auth.AuthenticationExtractor; +import server.haengdong.infrastructure.auth.JwtTokenProvider; +import server.haengdong.infrastructure.auth.TokenProperties; + +@RequiredArgsConstructor +@EnableConfigurationProperties(TokenProperties.class) +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + private final TokenProperties tokenProperties; + + @Value("${cors.max-age}") + private Long maxAge; + + @Value("${cors.allowed-origins}") + private String[] allowedOrigins; + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins(allowedOrigins) + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*") + .allowCredentials(true) + .maxAge(maxAge); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor()) + .addPathPatterns("/api/**") + .excludePathPatterns("/api/events"); + } + + @Bean + public AdminInterceptor adminInterceptor() { + return new AdminInterceptor(authService(), authenticationExtractor()); + } + + @Bean + public AuthService authService() { + return new AuthService(tokenProvider()); + } + + @Bean + public TokenProvider tokenProvider() { + return new JwtTokenProvider(tokenProperties); + } + + @Bean + public AuthenticationExtractor authenticationExtractor() { + return new AuthenticationExtractor(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/TokenProvider.java b/server/src/main/java/server/haengdong/domain/TokenProvider.java new file mode 100644 index 000000000..28e7956c3 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/TokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain; + +import java.util.Map; + +public interface TokenProvider { + + String createToken(Map<String, Object> payload); + + Map<String, Object> getPayload(String token); + + boolean validateToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/action/Action.java b/server/src/main/java/server/haengdong/domain/action/Action.java new file mode 100644 index 000000000..11f91fc38 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/Action.java @@ -0,0 +1,42 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Action { + + private static final long FIRST_SEQUENCE = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private Long sequence; + + public Action(Event event, Long sequence) { + this.event = event; + this.sequence = sequence; + } + + public static Action createFirst(Event event) { + return new Action(event, FIRST_SEQUENCE); + } + + public Action next() { + return new Action(event, sequence + 1); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/ActionRepository.java b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java new file mode 100644 index 000000000..2fde0ffa6 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/ActionRepository.java @@ -0,0 +1,23 @@ +package server.haengdong.domain.action; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface ActionRepository extends JpaRepository<Action, Long> { + + @Query(""" + SELECT a + FROM Action a + WHERE a.event = :event + ORDER BY a.sequence DESC + LIMIT 1 + """) + Optional<Action> findLastByEvent(@Param("event") Event event); + + Optional<Action> findByIdAndEvent(Long id, Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/action/BillAction.java new file mode 100644 index 000000000..943b40ce5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillAction.java @@ -0,0 +1,156 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillAction implements Comparable<BillAction> { + + public static final int MIN_TITLE_LENGTH = 1; + public static final int MAX_TITLE_LENGTH = 30; + public static final long MIN_PRICE = 1L; + public static final long MAX_PRICE = 10_000_000L; + private static final long DEFAULT_PRICE = 0L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + @Column(length = MAX_TITLE_LENGTH) + private String title; + + private Long price; + + @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List<BillActionDetail> billActionDetails = new ArrayList<>(); + + public BillAction(Action action, String title, Long price) { + validateTitle(title); + validatePrice(price); + this.action = action; + this.title = title.trim(); + this.price = price; + } + + private void validateTitle(String title) { + int titleLength = title.trim().length(); + if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_TITLE_INVALID); + } + } + + private void validatePrice(Long price) { + if (price < MIN_PRICE || price > MAX_PRICE) { + throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_INVALID); + } + } + + public static BillAction create(Action action, String title, Long price, CurrentMembers currentMembers) { + BillAction billAction = new BillAction(action, title, price); + billAction.resetBillActionDetails(currentMembers); + return billAction; + } + + public void resetBillActionDetails(CurrentMembers currentMembers) { + this.billActionDetails.clear(); + Iterator<Long> priceIterator = distributePrice(currentMembers.size()).iterator(); + + for (String member : currentMembers.getMembers()) { + BillActionDetail billActionDetail = new BillActionDetail(this, member, priceIterator.next(), false); + this.billActionDetails.add(billActionDetail); + } + } + + private void resetBillActionDetails() { + Iterator<Long> priceIterator = distributePrice(billActionDetails.size()).iterator(); + + billActionDetails.forEach(billActionDetail -> { + billActionDetail.updatePrice(priceIterator.next()); + billActionDetail.updateIsFixed(false); + }); + } + + private List<Long> distributePrice(int memberCount) { + if (memberCount == 0) { + return new ArrayList<>(); + } + long eachPrice = price / memberCount; + long remainder = price % memberCount; + + List<Long> results = Stream.generate(() -> eachPrice) + .limit(memberCount - 1) + .collect(Collectors.toList()); + results.add(eachPrice + remainder); + return results; + } + + public void update(String title, Long price) { + validateTitle(title); + validatePrice(price); + this.title = title.trim(); + this.price = price; + resetBillActionDetails(); + } + + public void addDetails(List<BillActionDetail> billActionDetails) { + billActionDetails.forEach(this::addDetail); + } + + private void addDetail(BillActionDetail billActionDetail) { + this.billActionDetails.add(billActionDetail); + billActionDetail.setBillAction(this); + } + + public boolean isFixed() { + return billActionDetails.stream() + .anyMatch(BillActionDetail::isFixed); + } + + public boolean isSamePrice(Long price) { + return this.price.equals(price); + } + + public Long findPriceByMemberName(String memberName) { + return billActionDetails.stream() + .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) + .map(BillActionDetail::getPrice) + .findFirst() + .orElse(DEFAULT_PRICE); + } + + public Long getSequence() { + return action.getSequence(); + } + + public Event getEvent() { + return action.getEvent(); + } + + @Override + public int compareTo(BillAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java new file mode 100644 index 000000000..ffdfe04a3 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -0,0 +1,61 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class BillActionDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private BillAction billAction; + + private String memberName; + + private Long price; + + private boolean isFixed; + + public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { + this.billAction = billAction; + this.memberName = memberName; + this.price = price; + this.isFixed = isFixed; + } + + public void updatePrice(Long price) { + this.price = price; + } + + public void updateIsFixed(boolean isFixed) { + this.isFixed = isFixed; + } + + public void updateMemberName(String name) { + this.memberName = name; + } + + public boolean hasMemberName(String memberName) { + return this.memberName.equals(memberName); + } + + public boolean isSameName(String memberName) { + return this.memberName.equals(memberName); + } + + public void setBillAction(BillAction billAction) { + this.billAction = billAction; + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java new file mode 100644 index 000000000..05de55304 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -0,0 +1,20 @@ +package server.haengdong.domain.action; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> { + + @Query(""" + select bd + from BillActionDetail bd + where bd.billAction = :billAction + """) + List<BillActionDetail> findAllByBillAction(BillAction billAction); + + List<BillActionDetail> findAllByBillAction_Action_EventAndMemberName(Event event, String memberName); +} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java new file mode 100644 index 000000000..817a63bf8 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -0,0 +1,27 @@ +package server.haengdong.domain.action; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillActionRepository extends JpaRepository<BillAction, Long> { + + @EntityGraph(attributePaths = {"action"}) + List<BillAction> findByAction_Event(Event event); + + void deleteByAction_EventAndActionId(Event event, Long actionId); + + Optional<BillAction> findByAction_Id(Long actionId); + + @Query(""" + select ba + from BillAction ba + where ba.action.event = :event and ba.action.sequence > :sequence + """) + List<BillAction> findByEventAndGreaterThanSequence(Event event, Long sequence); +} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java new file mode 100644 index 000000000..ba380aae5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java @@ -0,0 +1,81 @@ +package server.haengdong.domain.action; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class CurrentMembers { + + private final Set<String> members; + + public CurrentMembers() { + this(new HashSet<>()); + } + + protected CurrentMembers(Set<String> members) { + this.members = members; + } + + public static CurrentMembers of(List<MemberAction> memberActions) { + List<MemberAction> sortedMemberActions = getSortedMemberActions(memberActions); + Set<String> members = new HashSet<>(); + for (MemberAction memberAction : sortedMemberActions) { + String member = memberAction.getMemberName(); + if (memberAction.isSameStatus(MemberActionStatus.IN)) { + members.add(member); + continue; + } + members.remove(member); + } + + return new CurrentMembers(members); + } + + private static List<MemberAction> getSortedMemberActions(List<MemberAction> memberActions) { + return memberActions.stream() + .sorted(Comparator.comparing(MemberAction::getSequence)) + .toList(); + } + + public CurrentMembers addMemberAction(MemberAction memberAction) { + String memberName = memberAction.getMemberName(); + + Set<String> currentMembers = new HashSet<>(members); + + if (memberAction.isIn()) { + currentMembers.add(memberName); + } else { + currentMembers.remove(memberName); + } + return new CurrentMembers(currentMembers); + } + + public void validate(String memberName, MemberActionStatus memberActionStatus) { + if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); + } + } + + public boolean isEmpty() { + return members.isEmpty(); + } + + public boolean isNotEmpty() { + return !members.isEmpty(); + } + + public int size() { + return members.size(); + } + + public Set<String> getMembers() { + return Collections.unmodifiableSet(members); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java new file mode 100644 index 000000000..3faf65bde --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberAction.java @@ -0,0 +1,76 @@ +package server.haengdong.domain.action; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class MemberAction implements Comparable<MemberAction> { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 4; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private Action action; + + private String memberName; + + @Enumerated(EnumType.STRING) + private MemberActionStatus status; + + private Long memberGroupId; + + public MemberAction(Action action, String memberName, MemberActionStatus status, Long memberGroupId) { + validateMemberName(memberName); + this.action = action; + this.memberName = memberName; + this.status = status; + this.memberGroupId = memberGroupId; + } + + private void validateMemberName(String memberName) { + int memberLength = memberName.length(); + if (memberLength < MIN_NAME_LENGTH || memberLength > MAX_NAME_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + } + } + + public void updateMemberName(String memberName) { + validateMemberName(memberName); + this.memberName = memberName; + } + + public boolean isIn() { + return status == MemberActionStatus.IN; + } + + public boolean isSameStatus(MemberActionStatus memberActionStatus) { + return status == memberActionStatus; + } + + public Long getSequence() { + return action.getSequence(); + } + + @Override + public int compareTo(MemberAction o) { + return Long.compare(this.getSequence(), o.getSequence()); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java new file mode 100644 index 000000000..324ff9797 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -0,0 +1,53 @@ +package server.haengdong.domain.action; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface MemberActionRepository extends JpaRepository<MemberAction, Long> { + + @Query("select m from MemberAction m join fetch m.action where m.action.event = :event") + List<MemberAction> findAllByEvent(@Param("event") Event event); + + @Query(""" + select distinct m.memberName + from MemberAction m + where m.action.event = :event + """) + List<String> findAllUniqueMemberByEvent(Event event); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.event = :event + """) + void deleteAllByEventAndMemberName(Event event, String memberName); + + Optional<MemberAction> findByAction(Action action); + + @Modifying + @Query(""" + delete + from MemberAction m + where m.memberName = :memberName and m.action.sequence >= :sequence + """) + void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); + + List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName); + + boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); + + @Query(""" + select ma + from MemberAction ma + where ma.action.event = :event and ma.action.sequence < :sequence + """) + List<MemberAction> findByEventAndSequence(Event event, Long sequence); +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java new file mode 100644 index 000000000..76c5a66d4 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.action; + +import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public enum MemberActionStatus { + IN, + OUT, + ; + + public static MemberActionStatus of(String status) { + return Arrays.stream(MemberActionStatus.values()) + .filter(s -> s.name().equals(status)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID, + String.format(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID.getMessage(), status))); + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java new file mode 100644 index 000000000..7a707b9d8 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java @@ -0,0 +1,75 @@ +package server.haengdong.domain.action; + +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.function.Function; +import lombok.Getter; + +@Getter +public class MemberBillReport { + + private final Map<String, Long> reports; + + private MemberBillReport(Map<String, Long> reports) { + this.reports = reports; + } + + public static MemberBillReport createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { + PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); + PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); + + Map<String, Long> memberBillReports = initReports(memberActions); + CurrentMembers currentMembers = new CurrentMembers(); + while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { + if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { + MemberAction memberAction = sortedMemberActions.poll(); + currentMembers = currentMembers.addMemberAction(memberAction); + continue; + } + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + while (!sortedBillActions.isEmpty()) { + addBillAction(sortedBillActions, currentMembers, memberBillReports); + } + + return new MemberBillReport(memberBillReports); + } + + private static Map<String, Long> initReports(List<MemberAction> memberActions) { + return memberActions.stream() + .map(MemberAction::getMemberName) + .distinct() + .collect(toMap(Function.identity(), i -> 0L)); + } + + private static boolean isMemberActionTurn( + PriorityQueue<MemberAction> memberActions, + PriorityQueue<BillAction> billActions + ) { + MemberAction memberAction = memberActions.peek(); + BillAction billAction = billActions.peek(); + + return memberAction.getSequence() < billAction.getSequence(); + } + + private static void addBillAction( + PriorityQueue<BillAction> sortedBillActions, + CurrentMembers currentMembers, + Map<String, Long> memberBillReports + ) { + BillAction billAction = sortedBillActions.poll(); + if (currentMembers.isEmpty()) { + return; + } + + for (String currentMember : currentMembers.getMembers()) { + Long currentPrice = billAction.findPriceByMemberName(currentMember); + Long price = memberBillReports.get(currentMember) + currentPrice; + memberBillReports.put(currentMember, price); + } + } +} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java new file mode 100644 index 000000000..9e32bd733 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/action/MemberGroupIdProvider.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.action; + +import org.springframework.stereotype.Component; + +@Component +public class MemberGroupIdProvider { + + public Long createGroupId() { + return System.currentTimeMillis(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java new file mode 100644 index 000000000..bb5d53dbc --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -0,0 +1,70 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Event { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 20; + private static final String SPACES = " "; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @Embedded + @AttributeOverride(name = "value", column = @Column(name = "password")) + private Password password; + + private String token; + + public Event(String name, String password, String token) { + validateName(name); + this.name = name; + this.password = new Password(password); + this.token = token; + } + + private void validateName(String name) { + int nameLength = name.trim().length(); + if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, + String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", + MIN_NAME_LENGTH, + MAX_NAME_LENGTH, + name.length())); + } + if (isBlankContinuous(name)) { + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES, + String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); + } + } + + private boolean isBlankContinuous(String name) { + return name.contains(SPACES); + } + + public boolean isTokenMismatch(String token) { + return !this.token.equals(token); + } + + public boolean isPasswordMismatch(String rawPassword) { + return !password.matches(rawPassword); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java new file mode 100644 index 000000000..09526125e --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -0,0 +1,11 @@ +package server.haengdong.domain.event; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface EventRepository extends JpaRepository<Event, Long> { + + Optional<Event> findByToken(String token); +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventStep.java b/server/src/main/java/server/haengdong/domain/event/EventStep.java new file mode 100644 index 000000000..297abdb66 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventStep.java @@ -0,0 +1,28 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EventStep { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + private String name; + + private Long sequence; +} diff --git a/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java new file mode 100644 index 000000000..6450f0dcf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventTokenProvider.java @@ -0,0 +1,12 @@ +package server.haengdong.domain.event; + +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class EventTokenProvider { + + public String createToken() { + return UUID.randomUUID().toString(); + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Password.java b/server/src/main/java/server/haengdong/domain/event/Password.java new file mode 100644 index 000000000..375849dbf --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Password.java @@ -0,0 +1,52 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Embeddable; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@Embeddable +public class Password { + + public static final int PASSWORD_LENGTH = 4; + private static final Pattern PASSWORD_PATTERN = Pattern.compile(String.format("^\\d{%d}$", PASSWORD_LENGTH)); + private static final String HASH_ALGORITHM = "SHA-256"; + + private String value; + + public Password(String password) { + validatePassword(password); + this.value = encode(password); + } + + private void validatePassword(String password) { + Matcher matcher = PASSWORD_PATTERN.matcher(password); + if (!matcher.matches()) { + throw new HaengdongException(HaengdongErrorCode.EVENT_PASSWORD_FORMAT_INVALID); + } + } + + private String encode(String rawPassword) { + try { + MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM); + byte[] hashedPassword = digest.digest(rawPassword.getBytes()); + return Base64.getEncoder().encodeToString(hashedPassword); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("해시 알고리즘이 존재하지 않습니다."); + } + } + + public boolean matches(String rawPassword) { + String hashedPassword = encode(rawPassword); + return value.equals(hashedPassword); + } +} diff --git a/server/src/main/java/server/haengdong/exception/AuthenticationException.java b/server/src/main/java/server/haengdong/exception/AuthenticationException.java new file mode 100644 index 000000000..2efcb16e7 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/AuthenticationException.java @@ -0,0 +1,19 @@ +package server.haengdong.exception; + +import lombok.Getter; + +@Getter +public class AuthenticationException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public AuthenticationException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public AuthenticationException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/ErrorResponse.java b/server/src/main/java/server/haengdong/exception/ErrorResponse.java new file mode 100644 index 000000000..d0a2b01a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/ErrorResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.exception; + +public record ErrorResponse( + HaengdongErrorCode errorCode, + String message +) { + + public static ErrorResponse of(HaengdongErrorCode errorCode) { + return new ErrorResponse(errorCode, errorCode.getMessage()); + } + + public static ErrorResponse of(HaengdongErrorCode errorCode, String message) { + return new ErrorResponse(errorCode, message); + } +} diff --git a/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..0cee7cb4c --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/GlobalExceptionHandler.java @@ -0,0 +1,90 @@ +package server.haengdong.exception; + +import jakarta.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final String LOG_FORMAT = """ + \n\t{ + "RequestURI": "{} {}", + "RequestBody": {}, + "ErrorMessage": "{}" + \t} + """; + + @ExceptionHandler(AuthenticationException.class) + public ResponseEntity<ErrorResponse> authenticationException(HttpServletRequest req, AuthenticationException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public ResponseEntity<ErrorResponse> noResourceException(HttpRequestMethodNotSupportedException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_METHOD_NOT_SUPPORTED)); + } + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity<ErrorResponse> noResourceException(NoResourceFoundException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.NO_RESOURCE_REQUEST)); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity<ErrorResponse> httpMessageNotReadableException(HttpMessageNotReadableException e) { + log.warn(e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.MESSAGE_NOT_READABLE)); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + log.warn(e.getMessage(), e); + String errorMessage = e.getFieldErrors().stream() + .map(error -> error.getField() + " " + error.getDefaultMessage()) + .collect(Collectors.joining(", ")); + + return ResponseEntity.badRequest() + .body(ErrorResponse.of(HaengdongErrorCode.REQUEST_EMPTY, errorMessage)); + } + + @ExceptionHandler(HaengdongException.class) + public ResponseEntity<ErrorResponse> haengdongException(HttpServletRequest req, HaengdongException e) { + log.warn(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.badRequest() + .body(ErrorResponse.of(e.getErrorCode())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<ErrorResponse> handleException(HttpServletRequest req, Exception e) { + log.error(LOG_FORMAT, req.getMethod(), req.getRequestURI(), getRequestBody(req), e.getMessage(), e); + return ResponseEntity.internalServerError() + .body(ErrorResponse.of(HaengdongErrorCode.INTERNAL_SERVER_ERROR)); + } + + private String getRequestBody(HttpServletRequest req) { + try (BufferedReader reader = req.getReader()) { + return reader.lines().collect(Collectors.joining(System.lineSeparator() + "\t")); + } catch (IOException e) { + log.error("Failed to read request body", e); + return ""; + } + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java new file mode 100644 index 000000000..475d16c11 --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -0,0 +1,69 @@ +package server.haengdong.exception; + +import lombok.Getter; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.Password; + +@Getter +public enum HaengdongErrorCode { + + /* Domain */ + + EVENT_NOT_FOUND("존재하지 않는 행사입니다."), + EVENT_NAME_LENGTH_INVALID(String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", + Event.MIN_NAME_LENGTH, + Event.MAX_NAME_LENGTH)), + EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"), + EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)), + + ACTION_NOT_FOUND("존재하지 않는 액션입니다."), + + MEMBER_NAME_LENGTH_INVALID(String.format("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", + MemberAction.MIN_NAME_LENGTH, + MemberAction.MAX_NAME_LENGTH)), + MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), + MEMBER_NOT_EXIST("현재 참여하고 있지 않는 인원이 존재합니다."), + MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), + MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), + + MEMBER_ACTION_NOT_FOUND("존재하지 않는 멤버 액션입니다."), + MEMBER_ACTION_STATUS_INVALID("멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: %s"), + + BILL_ACTION_NOT_FOUND("존재하지 않는 지출 액션입니다."), + BILL_ACTION_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", + BillAction.MIN_TITLE_LENGTH, + BillAction.MAX_TITLE_LENGTH)), + BILL_ACTION_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", BillAction.MAX_PRICE)), + BILL_ACTION_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), + BILL_ACTION_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), + + /* Authentication */ + + PASSWORD_INVALID("비밀번호가 일치하지 않습니다."), + + TOKEN_NOT_FOUND("토큰이 존재하지 않습니다."), + TOKEN_EXPIRED("만료된 토큰입니다."), + TOKEN_INVALID("유효하지 않은 토큰입니다."), + + FORBIDDEN("접근할 수 없는 행사입니다."), + + /* Request Validation */ + + REQUEST_EMPTY("입력 값은 공백일 수 없습니다.") + + /* System */, + + MESSAGE_NOT_READABLE("읽을 수 없는 요청입니다."), + REQUEST_METHOD_NOT_SUPPORTED("지원하지 않는 요청 메서드입니다."), + NO_RESOURCE_REQUEST("존재하지 않는 자원입니다."), + INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생했습니다."), + ; + + private final String message; + + HaengdongErrorCode(String message) { + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongException.java b/server/src/main/java/server/haengdong/exception/HaengdongException.java new file mode 100644 index 000000000..b86fe4ffc --- /dev/null +++ b/server/src/main/java/server/haengdong/exception/HaengdongException.java @@ -0,0 +1,19 @@ +package server.haengdong.exception; + +import lombok.Getter; + +@Getter +public class HaengdongException extends RuntimeException { + + private final HaengdongErrorCode errorCode; + private final String message; + + public HaengdongException(HaengdongErrorCode errorCode) { + this(errorCode, errorCode.getMessage()); + } + + public HaengdongException(HaengdongErrorCode errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java new file mode 100644 index 000000000..4972de48a --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/AuthenticationExtractor.java @@ -0,0 +1,23 @@ +package server.haengdong.infrastructure.auth; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Arrays; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; + +public class AuthenticationExtractor { + + public String extract(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + throw new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND); + } + + return Arrays.stream(cookies) + .filter(cookie -> cookieName.equals(cookie.getName())) + .findFirst() + .orElseThrow(() -> new AuthenticationException(HaengdongErrorCode.TOKEN_NOT_FOUND)) + .getValue(); + } +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java new file mode 100644 index 000000000..18f867601 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/CookieProperties.java @@ -0,0 +1,15 @@ +package server.haengdong.infrastructure.auth; + +import java.time.Duration; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("cookie") +public record CookieProperties( + boolean httpOnly, + boolean secure, + String domain, + String path, + String sameSite, + Duration maxAge +) { +} diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java new file mode 100644 index 000000000..df9ec6a81 --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/JwtTokenProvider.java @@ -0,0 +1,54 @@ +package server.haengdong.infrastructure.auth; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import server.haengdong.domain.TokenProvider; + +public class JwtTokenProvider implements TokenProvider { + + private final TokenProperties tokenProperties; + + public JwtTokenProvider(TokenProperties tokenProperties) { + this.tokenProperties = tokenProperties; + } + + @Override + public String createToken(Map<String, Object> payload) { + Claims claims = Jwts.claims(new HashMap<>(payload)); + Date now = new Date(); + Date validity = new Date(now.getTime() + tokenProperties.expireLength()); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, tokenProperties.secretKey()) + .compact(); + } + + @Override + public Map<String, Object> getPayload(String token) { + return Jwts.parser() + .setSigningKey(tokenProperties.secretKey()) + .parseClaimsJws(token) + .getBody(); + } + + @Override + public boolean validateToken(String token) { + try { + Jws<Claims> claims = Jwts.parser().setSigningKey(tokenProperties.secretKey()).parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } +} + diff --git a/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java new file mode 100644 index 000000000..11dedcdbf --- /dev/null +++ b/server/src/main/java/server/haengdong/infrastructure/auth/TokenProperties.java @@ -0,0 +1,7 @@ +package server.haengdong.infrastructure.auth; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("security.jwt.token") +public record TokenProperties(String secretKey, Long expireLength) { +} diff --git a/server/src/main/java/server/haengdong/presentation/ActionController.java b/server/src/main/java/server/haengdong/presentation/ActionController.java new file mode 100644 index 000000000..657cb567e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/ActionController.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.response.MemberBillReportsResponse; + +@RequiredArgsConstructor +@RestController +public class ActionController { + + private final ActionService actionService; + + @GetMapping("/api/events/{eventId}/actions/reports") + public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("eventId") String token) { + List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); + + return ResponseEntity.ok() + .body(MemberBillReportsResponse.of(memberBillReports)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionController.java b/server/src/main/java/server/haengdong/presentation/BillActionController.java new file mode 100644 index 000000000..56e99337d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionController.java @@ -0,0 +1,55 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +@RequiredArgsConstructor +@RestController +public class BillActionController { + + private final BillActionService billActionService; + + @PostMapping("/api/events/{eventId}/bill-actions") + public ResponseEntity<Void> saveAllBillAction( + @PathVariable("eventId") String token, + @Valid @RequestBody BillActionsSaveRequest request + ) { + billActionService.saveAllBillAction(token, request.toAppRequests()); + + return ResponseEntity.ok() + .build(); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}") + public ResponseEntity<Void> updateBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionUpdateRequest request + ) { + billActionService.updateBillAction(token, actionId, request.toAppResponse()); + + return ResponseEntity.ok() + .build(); + } + + @DeleteMapping("/api/events/{eventId}/bill-actions/{actionId}") + public ResponseEntity<Void> deleteBillAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + billActionService.deleteBillAction(token, actionId); + + return ResponseEntity.ok() + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java new file mode 100644 index 000000000..5602e6777 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java @@ -0,0 +1,42 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; +import server.haengdong.presentation.response.BillActionDetailsResponse; + +@RequiredArgsConstructor +@RestController +public class BillActionDetailController { + + private final BillActionDetailService billActionDetailService; + + @GetMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<BillActionDetailsResponse> findBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + BillActionDetailsAppResponse appResponse = billActionDetailService.findBillActionDetails(token, actionId); + + return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); + } + + @PutMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") + public ResponseEntity<Void> updateBillActionDetails( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId, + @Valid @RequestBody BillActionDetailsUpdateRequest request + ) { + billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java new file mode 100644 index 000000000..34261042f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -0,0 +1,120 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.response.ActionsResponse; +import server.haengdong.presentation.response.EventDetailResponse; +import server.haengdong.presentation.response.EventResponse; +import server.haengdong.presentation.response.MembersResponse; +import server.haengdong.presentation.response.StepsResponse; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) +@RestController +public class EventController { + + private final EventService eventService; + private final AuthService authService; + private final CookieProperties cookieProperties; + + @PostMapping("/api/events") + public ResponseEntity<EventResponse> saveEvent(@Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + + String jwtToken = authService.createToken(eventResponse.eventId()); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .body(eventResponse); + } + + @GetMapping("/api/events/{eventId}") + public ResponseEntity<EventDetailResponse> findEvent(@PathVariable("eventId") String token) { + EventDetailResponse eventDetailResponse = EventDetailResponse.of(eventService.findEvent(token)); + + return ResponseEntity.ok(eventDetailResponse); + } + + @GetMapping("/api/events/{eventId}/actions") + public ResponseEntity<StepsResponse> findActions(@PathVariable("eventId") String token) { + StepsResponse stepsResponse = StepsResponse.of(eventService.findActions(token)); + + return ResponseEntity.ok(stepsResponse); + } + + @GetMapping("/api/events/{eventId}/actions/v2") + public ResponseEntity<ActionsResponse> findActions2(@PathVariable("eventId") String token) { + List<ActionAppResponse> actions = eventService.findActions(token); + ActionsResponse actionsResponse = ActionsResponse.of(actions); + + return ResponseEntity.ok(actionsResponse); + } + + @GetMapping("/api/events/{eventId}/members") + public ResponseEntity<MembersResponse> findAllMembers(@PathVariable("eventId") String token) { + MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); + + return ResponseEntity.ok(response); + } + + @PutMapping("/api/events/{eventId}/members/nameChange") + public ResponseEntity<Void> updateMember( + @PathVariable("eventId") String token, + @Valid @RequestBody MemberNamesUpdateRequest request + ) { + eventService.updateMember(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @PostMapping("/api/events/{eventId}/login") + public ResponseEntity<Void> loginEvent( + @PathVariable("eventId") String token, + @Valid @RequestBody EventLoginRequest request + ) { + eventService.validatePassword(request.toAppRequest(token)); + String jwtToken = authService.createToken(token); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .build(); + } + + @PostMapping("/api/events/{eventId}/auth") + public ResponseEntity<Void> authenticate(@PathVariable("eventId") String token) { + return ResponseEntity.ok().build(); + } + + private ResponseCookie createResponseCookie(String token) { + return ResponseCookie.from(authService.getTokenName(), token) + .httpOnly(cookieProperties.httpOnly()) + .secure(cookieProperties.secure()) + .domain(cookieProperties.domain()) + .path(cookieProperties.path()) + .sameSite(cookieProperties.sameSite()) + .maxAge(cookieProperties.maxAge()) + .build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberActionController.java new file mode 100644 index 000000000..1703245f7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/MemberActionController.java @@ -0,0 +1,60 @@ +package server.haengdong.presentation; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; +import server.haengdong.presentation.response.CurrentMembersResponse; + +@RequiredArgsConstructor +@RestController +public class MemberActionController { + + private final MemberActionService memberActionService; + + @PostMapping("/api/events/{eventId}/member-actions") + public ResponseEntity<Void> saveMemberAction( + @PathVariable("eventId") String token, + @RequestBody MemberActionsSaveRequest request + ) { + memberActionService.saveMemberAction(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/events/{eventId}/members/current") + public ResponseEntity<CurrentMembersResponse> getCurrentMembers(@PathVariable("eventId") String token) { + List<CurrentMemberAppResponse> currentMembers = memberActionService.getCurrentMembers(token); + + return ResponseEntity.ok() + .body(CurrentMembersResponse.of(currentMembers)); + } + + @DeleteMapping("/api/events/{eventId}/members/{memberName}") + public ResponseEntity<Void> deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberName") String memberName + ) { + memberActionService.deleteMember(token, memberName); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/events/{eventId}/member-actions/{actionId}") + public ResponseEntity<Void> deleteMemberAction( + @PathVariable("eventId") String token, + @PathVariable("actionId") Long actionId + ) { + memberActionService.deleteMemberAction(token, actionId); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java new file mode 100644 index 000000000..21c4bd60f --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java @@ -0,0 +1,21 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; + +public record BillActionDetailUpdateRequest( + + @NotBlank(message = "맴버 이름은 공백일 수 없습니다.") + String name, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + boolean isFixed +) { + public BillActionDetailUpdateAppRequest toAppRequest() { + return new BillActionDetailUpdateAppRequest(this.name, this.price, this.isFixed); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java new file mode 100644 index 000000000..fafbb8fd7 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; + +public record BillActionDetailsUpdateRequest( + @Valid @NotEmpty List<BillActionDetailUpdateRequest> members +) { + public BillActionDetailsUpdateAppRequest toAppRequest() { + return new BillActionDetailsUpdateAppRequest(members.stream() + .map(BillActionDetailUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java new file mode 100644 index 000000000..a47ff8316 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java @@ -0,0 +1,19 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionSaveRequest( + + @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") + String title, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price +) { + + public BillActionAppRequest toAppRequest() { + return new BillActionAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java new file mode 100644 index 000000000..680006816 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillActionUpdateAppRequest; + +public record BillActionUpdateRequest( + + @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") + String title, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price +) { + public BillActionUpdateAppRequest toAppResponse() { + return new BillActionUpdateAppRequest(title, price); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java new file mode 100644 index 000000000..6727d4cf1 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillActionAppRequest; + +public record BillActionsSaveRequest( + + @Valid @NotEmpty List<BillActionSaveRequest> actions +) { + + public List<BillActionAppRequest> toAppRequests() { + return actions.stream() + .map(BillActionSaveRequest::toAppRequest) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java new file mode 100644 index 000000000..a1286e903 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventLoginRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventLoginAppRequest; + +public record EventLoginRequest( + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + public EventLoginAppRequest toAppRequest(String token) { + return new EventLoginAppRequest(token, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java new file mode 100644 index 000000000..6bd7cd006 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventAppRequest; + +public record EventSaveRequest( + + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String eventName, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + + public EventAppRequest toAppRequest() { + return new EventAppRequest(eventName, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java new file mode 100644 index 000000000..41e95cc3c --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java @@ -0,0 +1,25 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; + +public record MemberActionsSaveRequest( + + @NotEmpty + List<String> members, + + @NotBlank(message = "멤버 액션은 공백일 수 없습니다.") + String status +) { + + public MemberActionsSaveAppRequest toAppRequest() { + List<MemberActionSaveAppRequest> appRequests = members.stream() + .map(name -> new MemberActionSaveAppRequest(name, status)) + .toList(); + + return new MemberActionsSaveAppRequest(appRequests); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java new file mode 100644 index 000000000..3cd2294ca --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.MemberNameUpdateAppRequest; + +public record MemberNameUpdateRequest( + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String before, + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String after +) { + + public MemberNameUpdateAppRequest toAppRequest() { + return new MemberNameUpdateAppRequest(before, after); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java new file mode 100644 index 000000000..872aa55de --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; + +public record MemberNamesUpdateRequest( + @Valid @NotEmpty List<MemberNameUpdateRequest> members +) { + + public MemberNamesUpdateAppRequest toAppRequest() { + return new MemberNamesUpdateAppRequest(members.stream() + .map(MemberNameUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java new file mode 100644 index 000000000..ea26ea769 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java @@ -0,0 +1,26 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse( + Long actionId, + String name, + Long price, + Long sequence, + boolean isFixed +) { + + public ActionResponse(Long actionId, String name, Long price, Long sequence) { + this(actionId, name, price, sequence, false); + } + + public static ActionResponse of(ActionAppResponse actionAppResponse) { + return new ActionResponse( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java new file mode 100644 index 000000000..ea46c5bd9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse2( + Long actionId, + String name, + Long price, + Long sequence, + String type +) { + + public static ActionResponse2 of(ActionAppResponse actionAppResponse) { + return new ActionResponse2( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.actionType().name() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..c8ae780e3 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + List<ActionResponse2> actions +) { + public static ActionsResponse of(List<ActionAppResponse> actions) { + return new ActionsResponse(actions.stream() + .map(ActionResponse2::of) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java new file mode 100644 index 000000000..10f71b82e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillActionDetailAppResponse; + +public record BillActionDetailResponse( + String name, + Long price, + boolean isFixed +) { + + public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { + return new BillActionDetailResponse( + billActionDetailAppResponse.name(), + billActionDetailAppResponse.price(), + billActionDetailAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java new file mode 100644 index 000000000..182e76db6 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.application.response.BillActionDetailsAppResponse; + +public record BillActionDetailsResponse( + List<BillActionDetailResponse> members +) { + + public static BillActionDetailsResponse of(BillActionDetailsAppResponse billActionDetailsAppResponse) { + return billActionDetailsAppResponse.billActionDetailAppResponses().stream() + .map(BillActionDetailResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java new file mode 100644 index 000000000..289cca4fa --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.CurrentMemberAppResponse; + +public record CurrentMembersResponse(List<String> memberNames) { + + public static CurrentMembersResponse of(List<CurrentMemberAppResponse> currentMembers) { + List<String> responses = currentMembers.stream() + .map(CurrentMemberAppResponse::name) + .toList(); + + return new CurrentMembersResponse(responses); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java new file mode 100644 index 000000000..c18694393 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventDetailAppResponse; + +public record EventDetailResponse(String eventName) { + + public static EventDetailResponse of(EventDetailAppResponse response) { + return new EventDetailResponse(response.eventName()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/EventResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java new file mode 100644 index 000000000..506f5e814 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/EventResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.EventAppResponse; + +public record EventResponse(String eventId) { + + public static EventResponse of(EventAppResponse eventAppResponse) { + return new EventResponse(eventAppResponse.token()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java new file mode 100644 index 000000000..0ea409202 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportResponse(String name, Long price) { + + public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { + return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java new file mode 100644 index 000000000..d350c4009 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MemberBillReportAppResponse; + +public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { + + public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { + List<MemberBillReportResponse> reports = memberBillReports.stream() + .map(MemberBillReportResponse::of) + .toList(); + + return new MemberBillReportsResponse(reports); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java new file mode 100644 index 000000000..0947d9e02 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MembersAppResponse; + +public record MembersResponse( + List<String> memberNames +) { + + public static MembersResponse of(MembersAppResponse response) { + return new MembersResponse(response.memberNames()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java new file mode 100644 index 000000000..55dd62c58 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -0,0 +1,27 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record StepResponse( + String stepName, + String type, + List<String> members, + List<ActionResponse> actions +) { + public static StepResponse of(String stepName, List<String> members, List<ActionAppResponse> actions) { + return new StepResponse( + stepName, + actions.get(0).actionTypeName(), + new ArrayList<>(members), + toActionsResponse(actions) + ); + } + + private static List<ActionResponse> toActionsResponse(List<ActionAppResponse> actions) { + return actions.stream() + .map(ActionResponse::of) + .toList(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java new file mode 100644 index 000000000..5f7573d67 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation.response; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +public record StepsResponse(List<StepResponse> steps) { + + public static StepsResponse of(List<ActionAppResponse> actions) { + List<StepResponse> steps = new ArrayList<>(); + List<String> currentMembers = new ArrayList<>(); + List<List<ActionAppResponse>> groups = createGroups(actions); + + int billStepCount = 0; + for (List<ActionAppResponse> group : groups) { + changeCurrentMembers(group, currentMembers); + if (group.get(0).actionType() == ActionType.BILL) { + billStepCount++; + } + StepResponse stepResponse = StepResponse.of(billStepCount + "차", currentMembers, group); + steps.add(stepResponse); + } + return new StepsResponse(steps); + } + + private static List<List<ActionAppResponse>> createGroups(List<ActionAppResponse> actions) { + List<List<ActionAppResponse>> groups = new ArrayList<>(); + + for (ActionAppResponse action : actions) { + if (groups.isEmpty() || isActionTypeChange(action, groups)) { + groups.add(new ArrayList<>()); + } + groups.get(groups.size() - 1).add(action); + } + + return groups; + } + + private static boolean isActionTypeChange(ActionAppResponse action, List<List<ActionAppResponse>> groups) { + List<ActionAppResponse> currentGroup = groups.get(groups.size() - 1); + return currentGroup.get(0).actionType() != action.actionType(); + } + + private static void changeCurrentMembers(List<ActionAppResponse> group, List<String> currentMembers) { + for (ActionAppResponse action : group) { + if (action.actionType() == ActionType.IN) { + currentMembers.add(action.name()); + continue; + } + if (action.actionType() == ActionType.OUT) { + currentMembers.remove(action.name()); + } + } + } +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml new file mode 100644 index 000000000..2ae503547 --- /dev/null +++ b/server/src/main/resources/application.yml @@ -0,0 +1,66 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:database + username: sa + password: + + h2: + console: + enabled: true + path: /h2-console + + jpa: + hibernate: + ddl-auto: create + properties: + hibernate: + format_sql: true + jdbc.time_zone: Asia/Seoul + show-sql: true + +cors: + max-age: 3600 + allowed-origins: http://localhost:3000, https://haengdong.pro, https://dev.haengdong.pro, https://app.haengdong.pro + +security: + jwt: + token: + secret-key: skdmeejEKJdkDjklDlkj123DKLJ3kDkeDkDKQMEOD1D90D8dE + expire-length: 604800000 # 1주일 + +cookie: + http-only: false + secure: false + path: / + same-site: none + max-age: 7D + +management: + endpoints: + web: + exposure: + include: health, metrics, logfile + +server: + servlet: + encoding: + charset: UTF-8 + enabled: true + force: true + +--- + +spring: + config: + import: classpath:config/application-prod.yml + activate: + on-profile: prod + +--- + +spring: + config: + import: classpath:config/application-dev.yml + activate: + on-profile: dev diff --git a/server/src/main/resources/config b/server/src/main/resources/config new file mode 160000 index 000000000..fa4270674 --- /dev/null +++ b/server/src/main/resources/config @@ -0,0 +1 @@ +Subproject commit fa42706743e6eb3f4fd8c34618614eff8ae94b3d diff --git a/server/src/main/resources/logback-spring.xml b/server/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..283b966a3 --- /dev/null +++ b/server/src/main/resources/logback-spring.xml @@ -0,0 +1,97 @@ +<configuration> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <!-- 콘솔에 로그 출력 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="ERROR-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-error.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="WARN-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>WARN</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-warn.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-warn.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="INFO-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>INFO</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-info.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-info.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <appender name="DEBUG-ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>DEBUG</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + <file>logs/spring-boot-application-debug.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>logs/spring-boot-application-debug.%d{yyyy-MM-dd}.log</fileNamePattern> + <maxHistory>30</maxHistory> + </rollingPolicy> + <encoder> + <!-- 날짜, 시간, 로그 레벨, 스레드 이름, 로거 이름, 메시지 형식 --> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <springProfile name="default"> + <root level="INFO"> + <appender-ref ref="CONSOLE"/> + </root> + </springProfile> + + <springProfile name="dev"> + <root level="INFO"> + <appender-ref ref="ERROR-ROLLING"/> + <appender-ref ref="WARN-ROLLING"/> + <appender-ref ref="INFO-ROLLING"/> + <appender-ref ref="DEBUG-ROLLING"/> + </root> + </springProfile> + + <springProfile name="prod"> + <root level="ERROR"> + <appender-ref ref="ERROR-ROLLING"/> + </root> + </springProfile> +</configuration> diff --git a/server/src/test/java/server/haengdong/application/ActionServiceTest.java b/server/src/test/java/server/haengdong/application/ActionServiceTest.java new file mode 100644 index 000000000..ee979b278 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ActionServiceTest.java @@ -0,0 +1,91 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class ActionServiceTest extends ServiceTestSupport { + + @Autowired + private ActionService actionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), + new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), + new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) + ); + List<BillAction> billActions = List.of( + new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), + new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) + ) + ); + memberActionRepository.saveAll(memberActions); + billActionRepository.saveAll(billActions); + + List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(event.getToken()); + + assertThat(responses) + .hasSize(3) + .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) + .containsExactlyInAnyOrder( + tuple("감자", 40_000L), + tuple("쿠키", 25_000L), + tuple("소하", 15_000L) + ); + } + + @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") + @Test + void getMemberBillReports1() { + assertThatThrownBy(() -> actionService.getMemberBillReports("invalid token")) + .isInstanceOf(HaengdongException.class) + .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java new file mode 100644 index 000000000..7074ce846 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java @@ -0,0 +1,111 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionDetailUpdateAppRequest; +import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionDetailServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionDetailService billActionDetailService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetailsTest() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 6000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 4000L, true); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( + event1.getToken(), action.getId()); + + assertThat(response.billActionDetailAppResponses()).hasSize(2) + .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) + .containsExactly( + tuple("토다리", 6000L), + tuple("쿠키", 4000L) + ); + } + + @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") + @Test + void updateBillActionDetailsTest1() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("토다리", 3000L, true), + new BillActionDetailUpdateAppRequest("쿠키", 4000L, true) + )); + assertThatCode( + () -> billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 총액이 일치하지 않습니다."); + } + + @DisplayName("지출 고정 금액을 수정한다.") + @Test + void updateBillActionDetailsTest2() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Action action = new Action(event1, 1L); + BillAction billAction = new BillAction(action, "뽕족", 10000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + + BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( + new BillActionDetailUpdateAppRequest("토다리", 3000L, true), + new BillActionDetailUpdateAppRequest("쿠키", 7000L, true) + )); + billActionDetailService.updateBillActionDetails(event1.getToken(), action.getId(), request); + + List<BillActionDetail> results = billActionDetailRepository.findAll(); + + assertThat(results).hasSize(2) + .extracting(BillActionDetail::getMemberName, BillActionDetail::getPrice) + .containsExactly( + tuple("토다리", 3000L), + tuple("쿠키", 7000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java new file mode 100644 index 000000000..39e52f80c --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -0,0 +1,229 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillActionUpdateAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillActionServiceTest extends ServiceTestSupport { + + @Autowired + private BillActionService billActionService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), requests); + + List<BillAction> actions = billActionRepository.findByAction_Event(savedEvent); + + assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) + .containsExactlyInAnyOrder( + tuple("뽕족", 10_000L, 3L), + tuple("인생맥주", 15_000L, 4L) + ); + } + + @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") + @Test + void saveAllBillActionTest1() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "망쵸", MemberActionStatus.IN, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + List<BillActionAppRequest> request = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + billActionService.saveAllBillAction(event.getToken(), request); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAll(); + + assertThat(billActionDetails) + .hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("백호", 5_000L), + tuple("망쵸", 5_000L), + tuple("백호", 7_500L), + tuple("망쵸", 7_500L) + ); + } + + @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() { + List<BillActionAppRequest> requests = List.of( + new BillActionAppRequest("뽕족", 10_000L), + new BillActionAppRequest("인생맥주", 15_000L) + ); + + assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + + assertAll( + () -> assertThat(updatedBillAction.getTitle()).isEqualTo("인생맥주"), + () -> assertThat(updatedBillAction.getPrice()).isEqualTo(20_000L) + ); + } + + @DisplayName("행사에 속하지 않은 지출 액션은 수정할 수 없다.") + @Test + void updateBillAction1() { + Event event1 = Fixture.EVENT1; + Event event2 = Fixture.EVENT2; + Event savedEvent1 = eventRepository.save(event1); + Event savedEvent2 = eventRepository.save(event2); + Action action1 = Action.createFirst(savedEvent1); + Action action2 = Action.createFirst(savedEvent2); + BillAction billAction1 = new BillAction(action1, "뽕족", 10_000L); + BillAction billAction2 = new BillAction(action2, "뽕족", 10_000L); + BillAction savedBillAction1 = billActionRepository.save(billAction1); + billActionRepository.save(billAction2); + + Long actionId = savedBillAction1.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") + @Test + void updateBillAction2() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L, true); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L, true); + BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L, true); + billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); + BillAction savedBillAction = billActionRepository.save(billAction); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(updatedBillAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("감자", 5000L), + tuple("고구마", 5000L), + tuple("당근", 5000L), + tuple("양파", 5000L) + ); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + BillAction billAction = new BillAction(new Action(event, 1L), "커피", 50_900L); + billActionRepository.save(billAction); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); + } + + @DisplayName("지출 내역을 삭제하면 지출 상세도 삭제된다.") + @Test + void deleteBillActionTest1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "백호", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "망쵸", MemberActionStatus.IN, 2L); + BillAction billAction = new BillAction(new Action(event, 3L), "커피", 50_900L); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L, false); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L, false); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + billActionRepository.save(billAction); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); + Long actionId = billAction.getAction().getId(); + + billActionService.deleteBillAction(event.getToken(), actionId); + + assertThat(billActionDetailRepository.findAll()).isEmpty(); + } + + @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") + @Test + void deleteBillAction1() { + assertThatThrownBy(() -> billActionService.deleteBillAction("소하망쵸", 1L)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java new file mode 100644 index 000000000..407fa1457 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -0,0 +1,231 @@ +package server.haengdong.application; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.mockito.BDDMockito.given; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.MemberNameUpdateAppRequest; +import server.haengdong.application.request.MemberNamesUpdateAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.event.EventTokenProvider; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class EventServiceTest extends ServiceTestSupport { + + @Autowired + private EventService eventService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private MemberActionRepository memberActionRepository; + + @MockBean + private EventTokenProvider eventTokenProvider; + + @DisplayName("행사를 생성한다") + @Test + void saveEventTest() { + EventAppRequest request = new EventAppRequest("test", "1234"); + given(eventTokenProvider.createToken()).willReturn("TOKEN"); + + EventAppResponse response = eventService.saveEvent(request); + + assertThat(response.token()).isEqualTo("TOKEN"); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + EventDetailAppResponse eventDetailAppResponse = eventService.findEvent(event.getToken()); + + assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); + } + + @DisplayName("행사에 속한 모든 액션을 조회한다.") + @Test + void findActionsTest() { + Event event = Fixture.EVENT1; + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", IN, 1L); + Action action1 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "쿠키", IN, 1L); + Action action2 = new Action(event, 3L); + BillAction billAction = new BillAction(action2, "뽕나무쟁이족발", 30000L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction, memberAction1)); + billActionRepository.save(billAction); + + List<ActionAppResponse> actionAppResponses = eventService.findActions(event.getToken()); + + assertThat(actionAppResponses).hasSize(3) + .extracting(ActionAppResponse::actionId, + ActionAppResponse::name, + ActionAppResponse::price, + ActionAppResponse::sequence, + ActionAppResponse::actionTypeName) + .containsExactly( + tuple(1L, "토다리", null, 1L, "IN"), + tuple(2L, "쿠키", null, 2L, "IN"), + tuple(3L, "뽕나무쟁이족발", 30000L, 3L, "BILL") + ); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() { + Event event = Fixture.EVENT1; + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + Action action3 = new Action(event, 3L); + Action action4 = new Action(event, 4L); + BillAction billAction = new BillAction(action3, "뽕나무쟁이족발", 30000L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(action4, "쿠키", OUT, 1L); + eventRepository.save(event); + billActionRepository.save(billAction); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MembersAppResponse membersAppResponse = eventService.findAllMembers(event.getToken()); + + assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); + } + + @DisplayName("행사 참여 인원들의 이름을 변경한다.") + @Test + void updateMember() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "쿠키", OUT, 3L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "쿠키", IN, 4L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "쿠키", OUT, 5L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of( + memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 + )); + + eventService.updateMember(event.getToken(), new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("토다리", "토쟁이") + ))); + + List<MemberAction> foundMemberActions = memberActionRepository.findAllByEvent(event); + assertThat(foundMemberActions) + .extracting(MemberAction::getId, MemberAction::getMemberName) + .contains( + tuple(memberAction1.getId(), "토쟁이"), + tuple(memberAction2.getId(), "쿡쿡"), + tuple(memberAction3.getId(), "웨디"), + tuple(memberAction4.getId(), "쿡쿡"), + tuple(memberAction5.getId(), "쿡쿡"), + tuple(memberAction6.getId(), "쿡쿡") + ); + } + + @DisplayName("이미 존재하는 인원의 이름으로 변경할 수 없다.") + @Test + void updateMember1() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("웨디", "토다리") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("존재하지 않는 인원은 변경할 수 없다.") + @Test + void updateMember2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿡쿡", "토쟁이"), + new MemberNameUpdateAppRequest("웨디", "말복") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("변경 전 참여 인원 이름이 중복될 수 없다.") + @Test + void updateMember3() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("쿠키", "토쟁이") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("변경 후 참여 인원 이름이 중복될 수 없다.") + @Test + void updateMember4() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "토다리", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "쿠키", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "웨디", IN, 2L); + eventRepository.save(event); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); + + MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( + new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), + new MemberNameUpdateAppRequest("토다리", "쿡쿡") + )); + + assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java new file mode 100644 index 000000000..c04f06026 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java @@ -0,0 +1,223 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.CurrentMembers; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class MemberActionFactoryTest extends ServiceTestSupport { + + @Autowired + private MemberActionFactory memberActionFactory; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") + @Test + void createMemberActionsTest() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action1 = new Action(event, 1L); + Action action2 = new Action(event, 2L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + + List<MemberAction> unorderedMemberActions = List.of(memberAction2, memberAction1); + CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); + Action startAction = new Action(event, 3L); + + assertThatThrownBy(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("인원 변동 액션을 생성한다.") + @Test + void createMemberActionsTest1() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + List<MemberAction> memberActions = memberActionFactory.createMemberActions(memberActionsSaveAppRequest, + currentMembers, startAction + ); + + assertThat(memberActions).hasSize(1) + .extracting(MemberAction::getAction, MemberAction::getMemberName, MemberAction::getStatus) + .containsExactly( + tuple(startAction, "토다리", MemberActionStatus.OUT) + ); + } + + @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") + @Test + void createMemberActionsTest2() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest3() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action1 = new Action(event, 1L); + MemberAction memberAction1 = new MemberAction(action1, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction1); + Action action2 = new Action(event, 2L); + MemberAction memberAction2 = new MemberAction(action2, "토다리", MemberActionStatus.OUT, 2L); + memberActionRepository.save(memberAction2); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("토다리", "IN"))); + Action startAction = new Action(event, 3L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") + @Test + void createMemberActionsTest4() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "토다리", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void createMemberActionTest5() { + Event event = eventRepository.save(Fixture.EVENT1); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") + @Test + void createMemberActionTest6() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") + @Test + void createMemberActionTest7() { + Event event = eventRepository.save(Fixture.EVENT1); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "IN") + )); + Action startAction = new Action(event, 1L); + CurrentMembers currentMembers = CurrentMembers.of(List.of()); + + assertThatCode( + () -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") + @Test + void createMemberActionTest8() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("쿠키", "OUT"), + new MemberActionSaveAppRequest("쿠키", "OUT") + )); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") + @Test + void createMemberActionTest9() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "쿠키", MemberActionStatus.IN, 1L); + memberActionRepository.save(memberAction); + + MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( + List.of( + new MemberActionSaveAppRequest("쿠키", "IN"), + new MemberActionSaveAppRequest("쿠키", "OUT") + )); + Action startAction = new Action(event, 2L); + CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); + + assertThatCode(() -> memberActionFactory.createMemberActions(request, currentMembers, startAction)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java new file mode 100644 index 000000000..b6d29444c --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -0,0 +1,251 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.groups.Tuple.tuple; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberActionSaveAppRequest; +import server.haengdong.application.request.MemberActionsSaveAppRequest; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; +import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.action.MemberActionRepository; +import server.haengdong.domain.action.MemberActionStatus; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class MemberActionServiceTest extends ServiceTestSupport { + + @Autowired + private MemberActionService memberActionService; + + @Autowired + private MemberActionRepository memberActionRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") + @Test + void saveMemberActionTest() { + Event event = eventRepository.save(Fixture.EVENT1); + Action action = new Action(event, 1L); + MemberAction memberAction = new MemberAction(action, "망쵸", IN, 1L); + memberActionRepository.save(memberAction); + + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") + @Test + void saveMemberActionTest1() { + Event event = eventRepository.save(Fixture.EVENT1); + Action actionOne = new Action(event, 1L); + MemberAction memberActionOne = new MemberAction(actionOne, "망쵸", IN, 1L); + memberActionRepository.save(memberActionOne); + + Action actionTwo = new Action(event, 2L); + MemberAction memberActionTwo = new MemberAction(actionTwo, "망쵸", OUT, 1L); + memberActionRepository.save(memberActionTwo); + + assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) + .doesNotThrowAnyException(); + } + + @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") + @Test + void saveMemberActionTest2() { + MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( + List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); + + assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") + @Test + void getCurrentMembers() { + assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "참여자", IN, 1L); + MemberAction memberAction2 = new MemberAction(new Action(event, 2L), "토다리", IN, 1L); + MemberAction memberAction3 = new MemberAction(new Action(event, 3L), "쿠키", IN, 1L); + MemberAction memberAction4 = new MemberAction(new Action(event, 4L), "소하", IN, 1L); + MemberAction memberAction5 = new MemberAction(new Action(event, 5L), "웨디", IN, 1L); + MemberAction memberAction6 = new MemberAction(new Action(event, 6L), "참여자", OUT, 1L); + memberActionRepository.saveAll( + List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); + + Event event2 = Fixture.EVENT2; + eventRepository.save(event2); + Action action2 = Action.createFirst(event2); + MemberAction anotherMemberAction = new MemberAction(action2, "참여자", IN, 1L); + memberActionRepository.save(anotherMemberAction); + + memberActionService.deleteMember(event.getToken(), "참여자"); + + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(5) + .extracting("memberName", "status") + .containsExactly( + tuple("토다리", IN), + tuple("쿠키", IN), + tuple("소하", IN), + tuple("웨디", IN), + tuple("참여자", IN) + ); + } + + @DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.") + @Test + void deleteMember1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + List<BillActionDetail> allByBillAction = billActionDetailRepository.findAllByBillAction(billAction); + System.out.println("allByBillAction = " + allByBillAction.isEmpty()); + + memberActionService.deleteMember(event.getToken(), "쿠키"); + + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + assertThat(billActionDetails).hasSize(2) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("웨디", 50_000L), + tuple("감자", 50_000L) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "토다리", IN, 5L); + MemberAction memberAction6 = createMemberAction(new Action(event, 6L), "토다리", OUT, 6L); + MemberAction memberAction7 = createMemberAction(new Action(event, 7L), "쿠키", OUT, 7L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5, + memberAction6, + memberAction7) + ); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<MemberAction> memberActions = memberActionRepository.findAll(); + + assertThat(memberActions).hasSize(4) + .extracting("id", "memberName", "status") + .containsExactly( + tuple(memberAction1.getId(), "토다리", IN), + tuple(memberAction3.getId(), "쿠키", IN), + tuple(memberAction4.getId(), "웨디", IN), + tuple(memberAction7.getId(), "쿠키", OUT) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.") + @Test + void deleteMemberAction1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List<BillActionDetail> billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("토다리", 25_000L), + tuple("쿠키", 25_000L), + tuple("웨디", 25_000L), + tuple("감자", 25_000L) + ); + } + + private MemberAction createMemberAction( + Action action, + String memberName, + MemberActionStatus memberActionStatus, + long memberGroupId + ) { + return new MemberAction(action, memberName, memberActionStatus, memberGroupId); + } +} diff --git a/server/src/test/java/server/haengdong/application/ServiceTestSupport.java b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java new file mode 100644 index 000000000..b0e2db0a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/ServiceTestSupport.java @@ -0,0 +1,11 @@ +package server.haengdong.application; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import server.haengdong.support.extension.DatabaseCleanerExtension; + +@ExtendWith(DatabaseCleanerExtension.class) +@SpringBootTest(webEnvironment= WebEnvironment.NONE) +abstract class ServiceTestSupport { +} diff --git a/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java new file mode 100644 index 000000000..39c2d0bb8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/ActionControllerDocsTest.java @@ -0,0 +1,70 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.ActionService; +import server.haengdong.application.response.MemberBillReportAppResponse; +import server.haengdong.presentation.ActionController; + +class ActionControllerDocsTest extends RestDocsSupport { + + private final ActionService actionService = mock(ActionService.class); + + @Override + protected Object initController() { + return new ActionController(actionService); + } + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) + .andDo( + document("getMemberBillReports", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), + fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액") + )) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java new file mode 100644 index 000000000..7ed6fe6c4 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionControllerDocsTest.java @@ -0,0 +1,128 @@ +package server.haengdong.docs; + +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.BillActionService; +import server.haengdong.presentation.BillActionController; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerDocsTest extends RestDocsSupport { + + private final BillActionService billActionService = mock(BillActionService.class); + + @Override + protected Object initController() { + return new BillActionController(billActionService); + } + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "쿠키토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .cookie(EVENT_COOKIE) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("createBillActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("actions").description("생성할 지출 액션 목록"), + fieldWithPath("actions[0].title").description("생성할 지출 액션의 제목"), + fieldWithPath("actions[0].price").description("생성할 지출 액션의 금액") + ) + )); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "웨디토큰"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("updateBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("지출 액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("title").description("수정할 지출 액션의 제목"), + fieldWithPath("price").description("수정할 지출 액션의 금액") + ) + )); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() throws Exception { + String eventId = "토다리토큰"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(document("deleteBillAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("지출 액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ) + )); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java new file mode 100644 index 000000000..f492195f3 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java @@ -0,0 +1,127 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.BillActionDetailController; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +public class BillActionDetailControllerDocsTest extends RestDocsSupport { + + private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); + + @Override + protected Object initController() { + return new BillActionDetailController(billActionDetailService); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetailsTest() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)) + .andDo( + document("findBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") + ) + ) + ); + } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateBillActionDetailsTest", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("전체 정산 수정 요청 목록"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + .description("참여자 정산 금액"), + fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + .description("참여자 정산 금액 수정 여부") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java new file mode 100644 index 000000000..88de2a3a6 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -0,0 +1,381 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.cookies.CookieDocumentation.responseCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.EventController; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + +public class EventControllerDocsTest extends RestDocsSupport { + + private final EventService eventService = mock(EventService.class); + private final AuthService authService = mock(AuthService.class); + private final CookieProperties cookieProperties = new CookieProperties( + true, true, "domain", "path", "none", Duration.ofDays(7) + ); + + @Override + protected Object initController() { + return new EventController(eventService, authService, cookieProperties); + } + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "쿠키 토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) + .andDo( + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String eventId = "망쵸토큰"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")) + .andDo( + document("getEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ) + ) + ); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("토다리")) + .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) + .andDo( + document("findAllEventMember", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) + ) + ); + } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateEventMemberName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("수정 후 참여자 이름") + ) + ) + ); + } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()) + .andDo( + document("eventLogin", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사 전체 액션 이력 조회") + @Test + void findActions() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) + .andExpect(jsonPath("$.steps[0].stepName").value(equalTo("0차"))) + .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[0].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) + + .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) + .andExpect(jsonPath("$.steps[1].stepName").value(equalTo("1차"))) + .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.steps[1].actions[0].price").value(equalTo(100))) + .andExpect(jsonPath("$.steps[1].actions[0].sequence").value(equalTo(2))) + + .andExpect(jsonPath("$.steps[1].actions[1].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.steps[1].actions[1].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.steps[1].actions[1].price").value(equalTo(1000))) + .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) + + .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) + .andExpect(jsonPath("$.steps[2].stepName").value(equalTo("1차"))) + .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.steps[2].actions[0].sequence").value(equalTo(4))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].stepName").type(JsonFieldType.STRING) + .description("스탭 이름"), + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("steps[].actions[].isFixed").type(JsonFieldType.BOOLEAN) + .description("지출 내역의 멤버별 고정 지출 금액 생성 여부") + ) + ) + ); + } + + @DisplayName("행사 전체 액션 이력 조회 v2") + @Test + void findActions2() throws Exception { + String token = "TOKEN"; + List<ActionAppResponse> actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[0].sequence").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].type").value(equalTo("IN"))) + + .andExpect(jsonPath("$.actions[1].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.actions[1].price").value(equalTo(100))) + .andExpect(jsonPath("$.actions[1].sequence").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[2].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.actions[2].price").value(equalTo(1000))) + .andExpect(jsonPath("$.actions[2].sequence").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[3].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[3].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[3].sequence").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].type").value(equalTo("OUT"))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("액션 타입") + ) + ) + ); + } + + @DisplayName("행사 어드민 권한을 확인한다.") + @Test + void authenticateTest() throws Exception { + String token = "TOKEN"; + mockMvc.perform(post("/api/events/{eventId}/auth", token) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + + .andDo( + document("authenticateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰").optional() + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java new file mode 100644 index 000000000..afd766c8f --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java @@ -0,0 +1,157 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberActionService; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.MemberActionController; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +public class MemberActionControllerDocsTest extends RestDocsSupport { + + private final MemberActionService memberActionService = mock(MemberActionService.class); + + @Override + protected Object initController() { + return new MemberActionController(memberActionService); + } + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("토큰 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("액션 대상 참여자 목록"), + fieldWithPath("status").type(JsonFieldType.STRING) + .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") + ) + ) + ); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))) + .andDo( + document("getCurrentMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("현재 탈주 가능한 참여 인원 이름 목록") + ) + ) + ); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMemberAction", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("actionId").description("액션 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteAllMemberActionByName", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberName").description("행사 참여자 이름") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/RestDocsSupport.java b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java new file mode 100644 index 000000000..3e6901ba8 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/RestDocsSupport.java @@ -0,0 +1,28 @@ +package server.haengdong.docs; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +@ExtendWith({RestDocumentationExtension.class}) +abstract class RestDocsSupport { + + protected MockMvc mockMvc; + + protected ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeEach + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.standaloneSetup(initController()) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + + protected abstract Object initController(); +} diff --git a/server/src/test/java/server/haengdong/domain/action/ActionTest.java b/server/src/test/java/server/haengdong/domain/action/ActionTest.java new file mode 100644 index 000000000..6ff25479c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/ActionTest.java @@ -0,0 +1,31 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class ActionTest { + + @DisplayName("액션의 초기 순서번호는 1이다.") + @Test + void createFirst() { + Event event = Fixture.EVENT1; + Action action = Action.createFirst(event); + + assertThat(action.getSequence()).isOne(); + } + + @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") + @Test + void next() { + Event event = Fixture.EVENT1; + Action action = new Action(event, 2L); + + Action nextAction = action.next(); + + assertThat(nextAction.getSequence()).isEqualTo(3L); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java new file mode 100644 index 000000000..ba1ab36f2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java @@ -0,0 +1,89 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; + +class BillActionTest { + + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) + void validateTitle(String title) { + Event event = EVENT1; + Action action = new Action(event, 1L); + Long price = 100L; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); + } + + @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + Event event = EVENT1; + Action action = new Action(event, 1L); + String title = "title"; + + assertThatThrownBy(() -> new BillAction(action, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + + @DisplayName("지출 내역을 올바르게 생성한다.") + @Test + void createBillAction() { + Event event = EVENT1; + Action action = new Action(event, 1L); + String title = "title"; + Long price = 1_000L; + + BillAction billAction = new BillAction(action, title, price); + + assertAll( + () -> assertThat(billAction.getAction()).isEqualTo(action), + () -> assertThat(billAction.getTitle()).isEqualTo(title), + () -> assertThat(billAction.getPrice()).isEqualTo(price) + ); + } + + @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed1() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 2_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail(BILL_ACTION, "감자", 1_000L, false), + new BillActionDetail(BILL_ACTION, "고구마", 1_000L, false) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(false); + } + + @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed2() { + BillAction fixedBillAction = new BillAction(new Action(EVENT1, 1L), "인생네컷", 5_000L); + + List<BillActionDetail> unfixedBillActionDetails = List.of( + new BillActionDetail(BILL_ACTION, "감자", 4_000L, true), + new BillActionDetail(BILL_ACTION, "고구마", 1_000L, true) + ); + fixedBillAction.addDetails(unfixedBillActionDetails); + + assertThat(fixedBillAction.isFixed()).isEqualTo(true); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java new file mode 100644 index 000000000..93148abd3 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java @@ -0,0 +1,97 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; + +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class CurrentMembersTest { + + @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") + @Test + void of() { + Event event = Fixture.EVENT1; + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "망쵸", IN, 1L), + new MemberAction(new Action(event, 2L), "백호", IN, 1L), + new MemberAction(new Action(event, 3L), "백호", OUT, 1L), + new MemberAction(new Action(event, 4L), "웨디", IN, 1L) + ); + + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + assertThat(currentMembers.getMembers()) + .containsExactlyInAnyOrder("망쵸", "웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") + @Test + void addMemberAction1() { + CurrentMembers currentMembers = new CurrentMembers(); + Event event = Fixture.EVENT1; + MemberAction memberAction = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); + Set<String> members = addedCurrentMembers.getMembers(); + + assertThat(members).hasSize(1) + .containsExactly("웨디"); + } + + @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") + @Test + void addMemberAction2() { + Event event = Fixture.EVENT1; + MemberAction memberAction1 = new MemberAction(new Action(event, 1L), "웨디", IN, 1L); + CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); + MemberAction memberAction2 = new MemberAction(new Action(event, 1L), "웨디", OUT, 1L); + + CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); + + assertThat(addedCurrentMembers.getMembers()).hasSize(0); + } + + @DisplayName("현재 참여중인 인원은 나갈 수 있다.") + @Test + void validate1() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); + + assertThatCode(() -> currentMembers.validate("토다리", OUT)) + .doesNotThrowAnyException(); + } + + @DisplayName("현재 참여중이지 않은 인원은 들어올 수 있다.") + @Test + void validate2() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); + + assertThatCode(() -> currentMembers.validate("토다리", IN)) + .doesNotThrowAnyException(); + } + + @DisplayName("현재 참여중인 인원은 들어올 수 없다.") + @Test + void validate3() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); + + assertThatCode(() -> currentMembers.validate("토다리", IN)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("현재 참여중이지 않은 인원은 나갈 수 없다.") + @Test + void validate4() { + CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); + + assertThatCode(() -> currentMembers.validate("토다리", OUT)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java new file mode 100644 index 000000000..02070a537 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java @@ -0,0 +1,56 @@ +package server.haengdong.domain.action; + +import static org.assertj.core.api.Assertions.assertThat; +import static server.haengdong.domain.action.MemberActionStatus.IN; +import static server.haengdong.domain.action.MemberActionStatus.OUT; +import static server.haengdong.support.fixture.Fixture.BILL_ACTION; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class MemberBillReportTest { + + @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByActions() { + Event event = Fixture.EVENT1; + List<BillAction> billActions = List.of( + new BillAction(new Action(event, 4L), "뽕족", 60_000L), + new BillAction(new Action(event, 7L), "인생네컷", 20_000L) + ); + billActions.get(0).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), + new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) + ) + ); + billActions.get(1).addDetails( + List.of( + new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), + new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) + ) + ); + List<MemberAction> memberActions = List.of( + new MemberAction(new Action(event, 1L), "소하", IN, 1L), + new MemberAction(new Action(event, 2L), "감자", IN, 1L), + new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), + new MemberAction(new Action(event, 5L), "감자", OUT, 2L) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + "감자", 40_000L, + "쿠키", 25_000L, + "소하", 15_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java new file mode 100644 index 000000000..12c0c0569 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -0,0 +1,65 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class EventTest { + + @DisplayName("공백 문자가 연속되지 않고, 이름이 2자 이상 20자 이하인 행사를 생성하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12", "12345678901234567890", "공 백", " 공백", "공백 ", " 공 백 "}) + void createSuccessTest(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .doesNotThrowAnyException(); + } + + @DisplayName("공백 문자가 연속되면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {" 공백", "공백 ", "공백 연속", "공 백"}) + void createFailTest1(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); + } + + @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "123456789012345678901"}) + void createFilTest2(String eventName) { + assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class) + .hasMessage(String.format("행사 이름은 1자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + } + + @DisplayName("비밀번호는 4자리 숫자 입니다.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String password) { + assertThatCode(() -> new Event("이름", password, "TEST_TOKEN")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("비밀번호가 다른지 검증한다.") + @Test + void isNotSamePassword() { + String rawPassword = "1234"; + Event event = new Event("이름", rawPassword, "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isFalse(); + } + + @DisplayName("비밀번호가 다른지 검증한다.") + @Test + void isNotSamePassword1() { + String rawPassword = "1234"; + Event event = new Event("이름", "5678", "TEST_TOKEN"); + + assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/PasswordTest.java b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java new file mode 100644 index 000000000..c504d3aa2 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/event/PasswordTest.java @@ -0,0 +1,19 @@ +package server.haengdong.domain.event; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.exception.HaengdongException; + +class PasswordTest { + + @DisplayName("비밀번호는 4자리 숫자 입니다.") + @ParameterizedTest + @ValueSource(strings = {"1", "12", "123", "12345", "adgd"}) + void validatePassword(String rawPassword) { + assertThatCode(() -> new Password(rawPassword)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java new file mode 100644 index 000000000..1de5889b5 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java @@ -0,0 +1,36 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.response.MemberBillReportAppResponse; + +class ActionControllerTest extends ControllerTestSupport { + + @DisplayName("참여자별 정산 현황을 조회한다.") + @Test + void getMemberBillReports() throws Exception { + List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( + new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + + given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/reports", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java new file mode 100644 index 000000000..4420e369c --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionControllerTest.java @@ -0,0 +1,97 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; +import server.haengdong.presentation.request.BillActionSaveRequest; +import server.haengdong.presentation.request.BillActionUpdateRequest; +import server.haengdong.presentation.request.BillActionsSaveRequest; + +class BillActionControllerTest extends ControllerTestSupport { + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveAllBillAction() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("뽕족", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "쿠키토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") + @Test + void saveAllBillAction1() throws Exception { + BillActionsSaveRequest request = new BillActionsSaveRequest( + List.of( + new BillActionSaveRequest("", 10_000L), + new BillActionSaveRequest("인생맥주", 10_000L) + ) + ); + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "소하토큰"; + + mockMvc.perform(post("/api/events/{eventId}/bill-actions", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } + + @DisplayName("지출 액션을 수정한다.") + @Test + void updateBillAction() throws Exception { + BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + + String requestBody = objectMapper.writeValueAsString(request); + String eventId = "웨디토큰"; + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBillAction() throws Exception { + String eventId = "토다리토큰"; + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("존재하지 않는 행사에 대한 지출 내역을 삭제할 수 없다.") + @Test + void deleteBillAction1() throws Exception { + String eventId = "이상해토큰"; + doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) + .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); + + mockMvc.perform(delete("/api/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + .andDo(print()) + .andExpect(status().isBadRequest()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java new file mode 100644 index 000000000..6b595ee27 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java @@ -0,0 +1,56 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.BillActionDetailAppResponse; +import server.haengdong.application.response.BillActionDetailsAppResponse; +import server.haengdong.presentation.request.BillActionDetailUpdateRequest; +import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; + +class BillActionDetailControllerTest extends ControllerTestSupport { + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( + List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); + given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) + .willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].name").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)); + } + + @DisplayName("참여자별 지출 금액을 수정한다.") + @Test + void updateBillActionDetailsTest() throws Exception { + List<BillActionDetailUpdateRequest> billActionDetailUpdateRequests = List.of( + new BillActionDetailUpdateRequest("소하", 10000L, true), + new BillActionDetailUpdateRequest("웨디", 20000L, true) + ); + BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + billActionDetailUpdateRequests); + + String json = objectMapper.writeValueAsString(request); + + mockMvc.perform(put("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java new file mode 100644 index 000000000..46489b1a5 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -0,0 +1,53 @@ +package server.haengdong.presentation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import server.haengdong.application.ActionService; +import server.haengdong.application.AuthService; +import server.haengdong.application.BillActionDetailService; +import server.haengdong.application.BillActionService; +import server.haengdong.application.EventService; +import server.haengdong.application.MemberActionService; + +@WebMvcTest( + controllers = { + EventController.class, + ActionController.class, + BillActionController.class, + MemberActionController.class, + BillActionDetailController.class + }, + excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} +) +abstract class ControllerTestSupport { + + @Autowired + protected MockMvc mockMvc; + + @Autowired + protected ObjectMapper objectMapper; + + @MockBean + protected EventService eventService; + + @MockBean + protected AuthService authService; + + @MockBean + protected ActionService actionService; + + @MockBean + protected MemberActionService memberActionService; + + @MockBean + protected BillActionService billActionService; + + @MockBean + protected BillActionDetailService billActionDetailService; +} diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java new file mode 100644 index 000000000..fcfe48d01 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -0,0 +1,111 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventDetailAppResponse; +import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.presentation.request.EventLoginRequest; +import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.MemberNameUpdateRequest; +import server.haengdong.presentation.request.MemberNamesUpdateRequest; + + +class EventControllerTest extends ControllerTestSupport { + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "망쵸토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + given(authService.createToken(eventId)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(jsonPath("$.eventId").value("망쵸토큰")); + } + + @DisplayName("토큰으로 행사를 조회한다.") + @Test + void findEventTest() throws Exception { + String eventId = "망쵸토큰"; + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); + + mockMvc.perform(get("/api/events/{eventId}", eventId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.eventName").value("행동대장 회식")); + } + + @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") + @Test + void findAllMembersTest() throws Exception { + MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); + given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames").isArray()) + .andExpect(jsonPath("$.memberNames[0]").value("토다리")) + .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); + } + + @DisplayName("행사 참여 인원의 이름을 수정한다.") + @Test + void updateMember() throws Exception { + String token = "TOKEN"; + MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( + new MemberNameUpdateRequest("토다링", "토쟁이"), + new MemberNameUpdateRequest("감자", "고구마") + )); + + String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + + mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사 어드민이 로그인한다.") + @Test + void loginEvent() throws Exception { + String token = "TOKEN"; + EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); + String requestBody = objectMapper.writeValueAsString(eventLoginRequest); + given(authService.createToken(token)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("eventToken"); + + mockMvc.perform(post("/api/events/{eventId}/login", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java new file mode 100644 index 000000000..f50c70a17 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java @@ -0,0 +1,74 @@ +package server.haengdong.presentation; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.presentation.request.MemberActionsSaveRequest; + +class MemberActionControllerTest extends ControllerTestSupport { + + @DisplayName("참여자 행동을 추가한다.") + @Test + void saveMemberActionTest() throws Exception { + MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( + List.of("웨디", "소하", "토다리", "쿠키"), "IN"); + + String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); + + mockMvc.perform(post("/api/events/{eventId}/member-actions", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List<CurrentMemberAppResponse> currentMemberAppResponses = List.of( + new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); + + given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) + .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))); + } + + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") + @Test + void deleteMemberAction() throws Exception { + String eventId = "망쵸토큰"; + Long actionId = 2L; + + mockMvc.perform(delete("/api/events/{eventId}/member-actions/{actionId}", eventId, actionId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + String memberName = "행동대장"; + + mockMvc.perform(delete("/api/events/{eventId}/members/{memberName}", eventId, memberName)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java new file mode 100644 index 000000000..051fcae0f --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java @@ -0,0 +1,63 @@ +package server.haengdong.presentation.response; + + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.ActionAppResponse.ActionType; + +class StepsResponseTest { + + @DisplayName("이웃한 같은 타입의 액션들을 그룹화 하여 응답객체를 생성한다.") + @Test + void of() { + List<ActionAppResponse> actions = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "백호", null, 2L, ActionType.IN), + new ActionAppResponse(3L, "감자탕", 10_000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "인생네컷", 10_000L, 4L, ActionType.BILL), + new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN), + new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN), + new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT), + new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT), + new ActionAppResponse(9L, "노래방", 20_000L, 9L, ActionType.BILL) + ); + + StepsResponse stepsResponse = StepsResponse.of(actions); + + StepsResponse expected = new StepsResponse( + List.of( + new StepResponse("0차", "IN", List.of("망쵸", "백호"), List.of( + new ActionResponse(1L, "망쵸", null, 1L), + new ActionResponse(2L, "백호", null, 2L) + )), + new StepResponse("1차", "BILL", List.of("망쵸", "백호"), List.of( + new ActionResponse(3L, "감자탕", 10_000L, 3L), + new ActionResponse(4L, "인생네컷", 10_000L, 4L) + )), + new StepResponse("1차", "IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( + new ActionResponse(5L, "소하", null, 5L), + new ActionResponse(6L, "웨디", null, 6L) + )), + new StepResponse("1차", "OUT", List.of("소하", "웨디"), List.of( + new ActionResponse(7L, "망쵸", null, 7L), + new ActionResponse(8L, "백호", null, 8L) + )), + new StepResponse("2차", "BILL", List.of("소하", "웨디"), List.of( + new ActionResponse(9L, "노래방", 20_000L, 9L) + )) + ) + ); + assertThat(stepsResponse).isEqualTo(expected); + } + + @DisplayName("액션이 없으면 빈 스탭들이 만들어진다.") + @Test + void ofEmpty() { + StepsResponse stepsResponse = StepsResponse.of(List.of()); + assertThat(stepsResponse.steps()).isEmpty(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java new file mode 100644 index 000000000..346e81d2d --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleaner.java @@ -0,0 +1,52 @@ +package server.haengdong.support.extension; + +import jakarta.annotation.PostConstruct; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.util.List; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +class DatabaseCleaner { + + private static final String REFERENTIAL_FORMAT = "set referential_integrity %b;"; + private static final String TRUNCATE_FORMAT = "truncate table %s restart identity;"; + + @PersistenceContext + private EntityManager em; + private String truncateTablesQuery; + + @PostConstruct + public void createTruncateQuery() { + List<String> tableNames = getTableNames(); + StringBuilder stringBuilder = new StringBuilder(); + + for (String tableName : tableNames) { + String truncateQuery = String.format(TRUNCATE_FORMAT, tableName); + stringBuilder.append(truncateQuery); + } + truncateTablesQuery = stringBuilder.toString(); + } + + private List<String> getTableNames() { + String sql = """ + select table_name + from information_schema.tables + where table_schema = 'PUBLIC' + """; + return em.createNativeQuery(sql).getResultList(); + } + + @Transactional + public void clear() { + em.clear(); + truncate(); + } + + private void truncate() { + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, false)).executeUpdate(); + em.createNativeQuery(truncateTablesQuery).executeUpdate(); + em.createNativeQuery(String.format(REFERENTIAL_FORMAT, true)).executeUpdate(); + } +} diff --git a/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java new file mode 100644 index 000000000..653ecadb3 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/extension/DatabaseCleanerExtension.java @@ -0,0 +1,19 @@ +package server.haengdong.support.extension; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +public class DatabaseCleanerExtension implements AfterEachCallback { + + @Override + public void afterEach(ExtensionContext context) { + DatabaseCleaner databaseCleaner = getDataCleaner(context); + databaseCleaner.clear(); + } + + private DatabaseCleaner getDataCleaner(ExtensionContext extensionContext) { + return SpringExtension.getApplicationContext(extensionContext) + .getBean(DatabaseCleaner.class); + } +} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java new file mode 100644 index 000000000..6844915d9 --- /dev/null +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -0,0 +1,15 @@ +package server.haengdong.support.fixture; + +import jakarta.servlet.http.Cookie; +import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.event.Event; + +public class Fixture { + + public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); + public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); + public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); + public static final Action ACTION = new Action(EVENT1, 1L); + public static final BillAction BILL_ACTION = new BillAction(ACTION, "뽕족", 30_000L); +}