diff --git a/.commitlintrc.json b/.commitlintrc.json new file mode 100644 index 0000000..6c23410 --- /dev/null +++ b/.commitlintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["@commitlint/config-conventional"], + "rules": { + "type-enum": [ + 2, + "always", + ["feat", "fix", "docs", "style", "refactor", "test", "build", "ci", "perf", "chore"] + ], + "type-case": [2, "always", "lower-case"], + "type-empty": [2, "never"], + "subject-case": [0], + "subject-empty": [2, "never"], + "subject-max-length": [2, "always", 72], + "subject-full-stop": [2, "never"], + "body-leading-blank": [2, "always"], + "scope-empty": [0] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index aa29a65..ec6d03e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,7 @@ __pycache__/ .DS_Store Thumbs.db +node_modules/ +npm-debug.log* +yarn-error.log +pnpm-debug.log diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..f8b4610 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/_/husky.sh" + +npx --no -- commitlint --edit "$1" diff --git a/README.md b/README.md index 4f4cb6e..0351039 100644 --- a/README.md +++ b/README.md @@ -56,4 +56,10 @@ uvicorn main:app --reload - ReDoc 문서: http://localhost:8000/redoc +### 4. Commit convention & commitlint + +- 이 레포는 commitlint/husky를 사용합니다. 클론 후 한 번만 실행: + - `npm install` + - `git config core.hooksPath .husky` (로컬 기기당 1회) + diff --git "a/docs/prompts/2\354\243\274\354\260\250/spec_prompt.md" "b/docs/prompts/2\354\243\274\354\260\250/spec_prompt.md" new file mode 100644 index 0000000..1df1e29 --- /dev/null +++ "b/docs/prompts/2\354\243\274\354\260\250/spec_prompt.md" @@ -0,0 +1,195 @@ +# PrimerFlow specification prompt + +## 1. 배경 및 목적 + +- 작성된 SeqLab 명세서 초안을 바탕으로 개발 팀원들과 공유할 기술 사양을 구체화함. 생물학적 요구사항(1-based Indexing, IUPAC 제한)을 개발 로직에 반영하고, View Culling 및 Auto Layout 등 핵심 기능의 구현 방향과 데이터 스키마를 사전 정의하여 혼선을 방지하고자 함. + +## 2. 프롬프트 (User Input) + +```text +너는 technique specification writer다. +목표: PCR primer design을 기능으로 하는 Seqlab의 software specification를 작성한다. +독자: 생물학 비전공인 개발자가 이 문서만으로 개발·테스트·출시 판단을 할 수 있어야 한다. + +출력 규칙(중요): +- 반드시 아래 "입력 정보"의 섹션 외의 내용 추가하지 말기. +- 반드시 아래 "출력 템플릿"의 섹션 순서/제목/번호를 절대 변경하지 말 것. +- 템플릿에 없는 섹션을 임의로 추가하지 말 것. (필요하면 해당 섹션의 "비고"에 적기) +- 각 항목을 가능한 한 구체적으로 채우고, 정보가 없으면 "TBD"로 두고 그 이유를 짧게 적기. +- 모호한 표현(예: 적당히/빠르게/최대한) 금지. 수치·조건·예외를 명시. +- 요구사항은 MUST/SHOULD/MAY로 구분. +- 기능 요구사항에는 최소 2개 이상의 예외 케이스를 포함. +- 마지막에 "확인 질문"은 최대 7개만. 이미 문서에 있는 내용은 다시 묻지 말 것. + +입력 정보: +🧬 PrimeFlow: Frontend Visualization Engine + +    +High-Performance PCR Primer Design & Visualization Platform +대용량 유전자 서열(10,000bp+)을 웹 브라우저에서 지연 없이 분석하고 시각화하는 프론트엔드 엔진 리포지토리입니다. +📖 프로젝트 개요 + +PrimeFlow는 생명과학 연구원들이 PCR 프라이머를 설계할 때 겪는 비효율을 해결하기 위한 웹 솔루션입니다. 본 리포지토리(Frontend)는 백엔드에서 분석된 유전자 데이터와 프라이머 후보군을 HTML5 Canvas를 활용해 시각적으로 표현하는 데 집중합니다. +💡 핵심 기술 (Key Features) + +Custom Rendering Engine: DOM 조작 방식이 아닌, Canvas API 기반의 자체 렌더링 엔진을 구현하여 10,000bp 이상의 데이터를 60fps로 부드럽게 렌더링합니다. +Optimization Algorithms: +View Culling: 이분 탐색(Binary Search)을 활용하여 화면 밖의 데이터 렌더링을 생략합니다. +Auto Layout: 그리디(Greedy) 알고리즘을 응용하여 겹치는 프라이머 구간을 자동으로 배치합니다. +Interactive UX: 행렬 변환(Matrix Transformation)을 적용한 정밀한 Zoom-In/Out 및 Panning 기능을 제공합니다. +🛠 기술 스택 (Tech Stack) + +Core: Next.js 14 (App Router), TypeScript +Graphics: HTML5 Canvas API (2D Context) +Styling: Tailwind CSS +State Management: Zustand +Data Fetching: SWR / TanStack Query +Deployment: Vercel +🏗️ 프로젝트 구조 (Project Architecture) + +PrimerFlow-FE/ +├── app/ # 🌐 [Main] 페이지 및 라우팅 (Next.js App Router) +│ ├── page.tsx # 메인 대시보드 화면 +│ └── layout.tsx # 전역 레이아웃 (Header, Font 등) +│ +├── components/ # 🧩 UI 컴포넌트 모음 +│ ├── canvas/ # ✨ [Core] 시각화 엔진 (GenomeCanvas, Controls 등) +│ └── ui/ # 공통 UI (Button, Input, Card 등) +│ +├── lib/ # 🧮 순수 함수 및 알고리즘 +│ ├── algorithms/ # [Optimization] 이분 탐색, 레이아웃 알고리즘 +│ ├── math/ # [Math] 좌표 변환(World <-> Screen), 행렬 연산 +│ └── parsers/ # [Data] FASTA 파싱 및 API 데이터 변환 +│ +├── store/ # 💾 전역 상태 관리 (Zustand) +│ └── useViewStore.ts # 줌 레벨, 뷰포트 위치 등 관리 +│ +├── docs/ # 📄 문서 및 프롬프트 아카이브 +│ └── prompts/ # AI 개발을 위한 기능 명세서(Spec) 모음 +│ +└── public/ # 🖼️ 정적 파일 (이미지, 아이콘) + +🚀 시작하기 (Getting Started) + +사전 요구사항 + +Node.js 18.17.0 이상 +npm 또는 yarn +설치 및 실행 + +# 1. 저장소 클론 +git clone [https://github.com/Seq-Lab/PrimerFlow-FE.git](https://github.com/Seq-Lab/PrimerFlow-FE.git)# 2. 프로젝트 폴더로 이동cd PrimerFlow-FE# 3. 패키지 설치 +npm install# 4. 환경 변수 설정 (.env.local 생성)# (백엔드 API 주소 설정 예시)# echo "NEXT_PUBLIC_API_URL=http://localhost:8000" > .env.local# 5. 개발 서버 실행 +npm run dev + +프로젝트 구조 + +PrimerFlow-BE/ +├─ api/ +│ ├─ deps.py +│ └─ v1/ +│ └─ endpoints/ # 엔드포인트 모음 +├─ schemas/ # Pydantic 모델 모음 +│ └─ schemas.py +├─ algorithms/ # 알고리즘 모음 +├─ docs/ # 협업 가이드 문서 모음 +│ └─ prompts/ +│ └─ strategy/ +├─ main.py # FastAPI 앱 엔트리포인트 +├─ requirements.txt # Python 패키지 목록 +├─ README.md +└─ .gitignore + +개발 환경 설정 + +1. 가상환경 생성 및 활성화 + +Windowspython -m venv .venv +.\.venv\Scripts\Activate.ps1 # PowerShell# 또는 +.\.venv\Scripts\activate.bat # cmd + +macOS / Linuxpython3 -m venv .venvsource .venv/bin/activate + +2. 의존성 설치 + +pip install -r requirements.txt + +3. 개발 서버 실행 + +uvicorn main:app --reload + +기본 엔드포인트: http://localhost:8000/ +OpenAPI 문서: http://localhost:8000/docs +ReDoc 문서: http://localhost:8000/redoc + +출력 템플릿: +1. 개요 +1.1 목적 +1.2 범위(포함/제외) +1.3 용어 정의 + +2. 이해관계자/권한 +2.1 사용자 유형 +2.2 권한 매트릭스(역할별 가능/불가) + +3. 요구사항 +3.1 기능 요구사항 (FR) +- FR-001: +  - 설명: +  - 입력: +  - 처리 로직: +  - 출력: +  - 예외/에러: +  - 우선순위(MUST/SHOULD/MAY): +  - 수용 기준(AC): +(반복) +3.2 비기능 요구사항 (NFR) +- 성능/지연: +- 가용성: +- 보안/개인정보: +- 로깅/감사: +- 호환성: +- 접근성: + +4. 유저 플로우/시나리오 +4.1 정상 시나리오 +4.2 실패/예외 시나리오 + +5. API/데이터 설계(해당 시) +5.1 엔티티/스키마 +5.2 API 목록(엔드포인트/요청/응답/에러코드) +5.3 상태/이벤트 + +6. UI 규칙(해당 시) +6.1 화면 목록 +6.2 화면별 규칙(입력 검증/에러 메시지 문구/빈 상태) + +7. 테스트 전략 +7.1 테스트 케이스 요약 +7.2 경계값/부하/보안 테스트 + +8. 릴리즈/운영 +8.1 롤아웃/마이그레이션 +8.2 모니터링 지표/알람 +8.3 롤백 계획 + +9. 리스크/의존성 +9.1 리스크 +9.2 외부 의존성 + +10. 확인 질문(최대 7개) +``` + +## 3. AI 응답 요약 (AI Output) + +- 핵심 기술 사양 (Core Specifications) + - 좌표계 규칙: UI/API는 1-based (생물학 표준), 내부 연산은 0-based (배열 인덱스) 사용. (렌더링 시 변환 필수) + - 입력 데이터: A, C, G, T, N 5개 문자만 허용 (IUPAC 확장 문자 불허). + - 성능 목표: 10,000bp 이상 데이터를 Canvas로 60fps 렌더링. +- 기능적 요구사항 및 비기능적 요구사항 +- 유저 시나리오 + +## 4. 결과 및 적용 (Result) + +- GPT와 Gemini에 각각 동일한 프롬프트를 입력하여, 둘의 내용들을 정독한 후 통합한 버전으로 작성하였다. +- 시나리오와 제한사항들을 설계하여, 이후 개발과정과 테스트 케이스 설계의 기준으로 설정할 수 있다. \ No newline at end of file diff --git a/docs/spec_API&Data.md b/docs/spec_API&Data.md new file mode 100644 index 0000000..9e939b7 --- /dev/null +++ b/docs/spec_API&Data.md @@ -0,0 +1,82 @@ +# 5. API 및 데이터 설계 (API & Data Design) + +## 5.1 엔티티 및 스키마 (Entity Schema) + +백엔드와 프론트엔드 간 교환되는 핵심 데이터 모델입니다. + +### 1) GenomeSequence +사용자가 입력한 유전자 서열의 파싱 결과입니다. + +```typescript +interface GenomeSequence { + id: string; // 고유 ID + name: string; // FASTA Header (서열 이름) + sequence: string; // 정규화된 유전자 서열 (A/C/G/T/N...) + length_bp: number; // 서열 길이 +} +``` +### 2) PrimerCandidate + +```typescript +interface PrimerCandidate { + id: string; // 후보 ID + sequence: string; // 프라이머 서열 + start_bp: number; // 시작 위치 (TBD: 0-based vs 1-based 기준 확정 필요) + end_bp: number; // 종료 위치 + strand: "forward" | "reverse"; // 방향 + metrics: { // (TBD) 제공 필드 확정 필요 + tm_c?: number; // 녹는점 (Melting Temperature) + gc_percent?: number; // GC 함량 + penalties?: any; // 패널티 점수 등 + }; +} +``` +### 3) PrimerDesignResponse +```typescript +interface PrimerDesignResponse { + genome: GenomeSequence; // 분석된 게놈 정보 (요약) + candidates: PrimerCandidate[]; // 생성된 후보 목록 + meta: { // (TBD) 메타 데이터 + params?: any; // 요청 시 사용된 파라미터 + timestamp?: string; // 생성 시간 + }; +} +``` +## 5.2 API 목록 (API Endpoints) +Note: 백엔드는 FastAPI를 사용하며 OpenAPI(/docs)를 제공합니다. 정확한 경로는 개발 착수 시 확정(TBD)됩니다. +1) 프라이머 설계 요청 (Design Primers) +- Endpoint: POST /api/design (예상, TBD) +- Request:서열 데이터 (Sequence String) +설계 파라미터 (TBD: Target Product Size, Tm Range 등) +- Response: PrimerDesignResponse +- Status Codes & Errors: + - 200 OK: 성공 + - 400 Bad Request: 입력 검증 실패 (잘못된 서열 문자, 파라미터 오류) + - 413 Payload Too Large: 입력 서열이 너무 큼 (TBD: 상한선 정책) + - 500 Internal Server Error: 서버 내부 알고리즘 오류 + +2) 헬스 체크 (Health Check) +- Endpoint: GET / 또는 GET /health (TBD) +- Response: 서버 상태 문자열 또는 JSON (TBD) + +## 5.3 상태 및 이벤트 관리 (State & Events) +프론트엔드(Zustand)에서 관리해야 할 전역 상태와 주요 이벤트 흐름입니다. + +#### 1. 전역 상태 (Global State - Zustand) - 상태 변수 +#### 타입설명 +* viewportStartBpnumber: 현재 뷰포트 시작 위치 (1-based 권장) +* viewportEndBpnumber: 현재 뷰포트 종료 위치 +* zoomLevelnumber: 캔버스 확대 배율 +* selectedPrimerIdstring: 사용자가 클릭하여 선택한 프라이머 +* IDhoveredPrimerIdstring(TBD): 마우스 오버 중인 프라이머 +* IDfilterSortStateobject(TBD): 후보 리스트 필터/정렬 조건 +#### 2. 주요 이벤트 (Key Events) - 데이터 흐름과 UI 반응을 트리거하는 핵심 이벤트 +#### 데이터 처리 +* SEQUENCE_PARSED: FASTA 파싱 완료 시 +* DESIGN_REQUESTED: 설계 요청 시작 (로딩 UI 표시) +* DESIGN_SUCCEEDED: 결과 수신 완료 (캔버스 렌더링 시작) +* DESIGN_FAILED: 요청 실패 (에러 배너 표시) +#### 상호작용 +* VIEWPORT_CHANGED: 줌/팬 동작으로 보고 있는 구간 변경 시 +* PRIMER_SELECTED: 프라이머 클릭 시 (상세 패널 표시) +* PRIMER_DESELECTED: 빈 공간 클릭 또는 선택 해제 시 \ No newline at end of file diff --git a/docs/spec_QA&Op&Risk.md b/docs/spec_QA&Op&Risk.md new file mode 100644 index 0000000..10d4cd7 --- /dev/null +++ b/docs/spec_QA&Op&Risk.md @@ -0,0 +1,35 @@ +### 📄 5. `docs/05_QA_Ops_Risks.md` + +# 7. 테스트 전략 + +## 7.1 테스트 케이스 +* **파서:** FASTA 정상/비정상 입력, 허용 문자 검증. +* **알고리즘:** View Culling 경계값 계산, Auto Layout 겹침 방지. +* **UI/E2E:** 입력 → 설계 → 렌더링 → 내보내기 흐름 검증. +* **성능:** 10,000bp 이상 데이터에서 프레임/지연 측정. + +## 7.2 경계값 테스트 (Boundary Testing) +* 서열 길이: 1bp, 9,999bp, 10,000bp. +* 뷰포트: `start=0`, `start>end` (오류 케이스). + +--- + +# 8. 릴리즈 및 운영 + +* **배포:** Frontend는 **Vercel**, Backend는 FastAPI. +* **환경 변수:** `NEXT_PUBLIC_API_URL` 필수. +* **모니터링:** API 실패율, 주요 UI 액션 실패율. +* **롤백:** Vercel 배포 히스토리 기반 즉시 롤백. + +--- + +# 9. 리스크 및 의존성 + +## 9.1 리스크 +* 대용량 데이터 처리 시 브라우저 메모리 증가로 인한 성능 저하. +* 캔버스 UI의 접근성(스크린 리더) 대응 어려움. +* **0-based vs 1-based** 좌표계 불일치 시 시각화 오류 발생 가능성. + +## 9.2 기술 스택 (Dependencies) +* **Frontend:** Next.js 16, TypeScript, Tailwind, Zustand, SWR/TanStack Query. +* **Backend:** FastAPI (Python). \ No newline at end of file diff --git a/docs/spec_Questions.md b/docs/spec_Questions.md new file mode 100644 index 0000000..0a2e3ae --- /dev/null +++ b/docs/spec_Questions.md @@ -0,0 +1,11 @@ +# 10. 확인 질문 (To Be Discussed) + +개발 착수 전 확정이 필요한 사항들입니다. + +1. **API 스펙 확정:** 설계 요청 API의 정확한 엔드포인트/파라미터/응답 스키마(OpenAPI 기준)가 필요합니다. +2. **좌표계 통일:** API 응답의 `start/end`가 **0-based**인지 **1-based**인지 명확해야 합니다. (문서 상 1-based 권장) +3. **IUPAC 확장:** 서열 입력 시 `A/C/G/T/N` 외에 **확장 문자(R, Y 등)**를 허용할 것인지 결정해야 합니다. +4. **성능 기준:** 60fps 합격 기준(디바이스 사양, 데이터 상한선) 정의가 필요합니다. +5. **내보내기 포맷:** CSV, TSV, FASTA 중 필수 포맷 결정이 필요합니다. +6. **필터/정렬:** 프론트엔드 처리 vs 백엔드 파라미터 처리 방식 결정. +7. **사용자 권한:** 단일 사용자(무로그인) 모드인지, 관리자 기능이 필요한지 확정 필요. \ No newline at end of file diff --git a/docs/spec_overview.md b/docs/spec_overview.md new file mode 100644 index 0000000..569d780 --- /dev/null +++ b/docs/spec_overview.md @@ -0,0 +1,43 @@ +# 1. 개요 (Overview) + +## 1.1 목적 +본 문서는 생명과학 연구원들이 PCR 프라이머(Primer)를 설계할 때 겪는 비효율을 해결하기 위한 웹 솔루션 **PrimerFlow**의 기술 사양을 정의한다. +본 시스템은 10,000bp 이상의 대용량 유전자 서열 데이터를 백엔드에서 분석하고, 프론트엔드(PrimeFlow Engine)에서 웹 브라우저 지연 없이 **60fps로 시각화**하는 것을 목적으로 한다. + +## 1.2 범위 (Scope) + +### 포함 (In-Scope) +* **Frontend:** Next.js 16 기반의 웹 애플리케이션 구현. HTML5 Canvas API를 활용한 Custom Rendering Engine, UI 컴포넌트, 전역 상태 관리(Zustand). +* **Backend:** FastAPI 기반의 REST API 서버. 유전자 데이터 분석 및 PCR 프라이머 설계 알고리즘 제공. +* **Algorithm:** View Culling(이분 탐색), Auto Layout(Greedy), 좌표 변환(Matrix Transformation). +* **Infra:** Vercel 배포(FE) 및 로컬 개발 환경 구성. + +### 제외 (Out-Scope) +* 사용자 인증/인가 시스템 (입력 정보에 명시되지 않음, TBD). +* 실제 실험 장비와의 하드웨어 연동. + +## 1.3 용어 정의 (Terminology) + +| 용어 | 정의 | 비고 | +| :--- | :--- | :--- | +| **bp (Base Pair)** | 유전자 서열의 길이를 나타내는 단위. | 시각화 시 X축 좌표의 기준 단위가 됨. | +| **PCR Primer** | DNA 중합효소 연쇄 반응(PCR)을 위해 필요한 짧은 유전자 서열 조각. | UI 상에서 유전자 위에 겹쳐지는 '구간'으로 표현됨. | +| **FASTA** | 유전자 서열 데이터를 표현하는 텍스트 기반 포맷. | `lib/parsers/`에서 파싱해야 할 입력 데이터 형식. | +| **View Culling** | 현재 화면(Viewport)에 보이지 않는 데이터를 렌더링에서 제외하는 최적화 기법. | 이분 탐색(Binary Search) 사용. | +| **Canvas API** | HTML5 `` 요소를 통해 비트맵 그래픽을 즉시 모드로 그리는 수단. | DOM 조작 대신 사용됨. | +| **Coordinate System** | 유전자 위치를 나타내는 숫자 체계. 본 프로젝트는 **생물학 표준인 1-based Indexing**을 따른다. | UI 및 API의 모든 위치 값은 1부터 시작한다. (0번 아님) | +| **Range (구간)** | 시작(Start)과 끝(End)을 포함하는 **Closed Interval [Start, End]**. | Python 슬라이싱 `[Start:End)`과 다르므로 주의. | + +--- + +# 2. 이해관계자 및 권한 + +## 2.1 사용자 유형 +* **Researcher (연구원/사용자):** 서열을 입력하고 프라이머 후보를 조회/선택/내보내기 한다. +* **Developer (개발자):** 디버그/성능 측정/렌더링 검증을 수행한다. + +## 2.2 권한 매트릭스 +| 역할 | 가능 (Allowed) | 불가 (Disallowed) | +| :--- | :--- | :--- | +| **Researcher** | 서열 입력(FASTA), 프라이머 후보 조회, 캔버스 탐색(Zoom/Pan), 후보 선택/비교, 결과 내보내기 | 배포 설정 변경, API URL 변경(프로덕션) | +| **Developer** | 성능 오버레이/디버그 로그 활성화(개발 환경), 샘플 데이터 로드(개발용) | (기본) 운영 데이터 변경/관리 기능 | \ No newline at end of file diff --git a/docs/spec_requirement.md b/docs/spec_requirement.md new file mode 100644 index 0000000..4ec0aea --- /dev/null +++ b/docs/spec_requirement.md @@ -0,0 +1,48 @@ +# 3. 요구사항 (Requirements) + +## 3.1 기능 요구사항 (Functional Requirements) + +### FR-001: FASTA 서열 입력/로딩 +* **설명:** 사용자는 유전자 서열을 FASTA 형식으로 붙여넣거나(또는 파일 업로드) 분석을 시작할 수 있어야 한다. +* **처리 로직:** + 1. `lib/parsers`에서 FASTA 파싱 (헤더/서열 추출) + 2. 서열 문자열 정규화 (대문자 변환, 공백/개행 제거) + 3. 허용 문자 검증 (**기본: A/C/G/T/N**) +* **우선순위:** **MUST** +* **예외 처리:** + * FASTA 파싱 실패 시: “FASTA 형식을 확인해 주세요. A/C/G/T/N 문자만 허용됩니다.” + * 서열 길이 오류 시: “서열 길이가 허용 범위를 벗어났습니다. (현재: {len}bp)” + +### FR-002: 대용량 유전자 서열 시각화 (Custom Rendering Engine) +* **설명:** 10,000bp 이상의 유전자 데이터를 HTML5 Canvas에 DOM 조작 없이 렌더링해야 한다. +* **처리 로직:** `components/canvas/` 로드 → Canvas 2D Context 획득 → Loop 드로잉 (`ctx.lineTo`, `ctx.stroke`) +* **우선순위:** **MUST** +* **수용 기준:** 10,000bp 데이터 로드 시 스크롤/줌 동작 중 **60fps 유지**. + +### FR-003: 뷰 컬링(View Culling) 최적화 +* **설명:** 현재 뷰포트(화면) 밖의 데이터는 렌더링 연산에서 제외한다. +* **처리 로직:** + 1. UI의 **1-based 좌표**를 내부 연산용 **0-based 인덱스**로 변환 (`Index = Coordinate - 1`) + 2. `lib/algorithms/`의 이분 탐색(Binary Search)으로 렌더링 범위 탐색. +* **우선순위:** **SHOULD** + +### FR-004: 프라이머 설계 요청 (백엔드 호출) +* **설명:** SWR/TanStack Query로 백엔드에 설계를 요청하고 응답을 캐싱한다. +* **우선순위:** **MUST** +* **수용 기준:** 요청 성공 시 후보 리스트와 캔버스 렌더링이 동시에 갱신된다. + +### FR-005: 프라이머 자동 레이아웃 (Auto Layout) +* **설명:** 겹치는 프라이머 구간을 자동으로 Y축(높이)을 달리하여 배치한다. +* **처리 로직:** `lib/algorithms/`의 **Greedy 알고리즘** 응용. 충돌(Collision) 감지 시 Layer 레벨 증가. +* **우선순위:** **MUST** + +### FR-006: 인터랙티브 UX (Zoom/Pan) +* **설명:** 마우스/트랙패드를 통한 줌인/아웃 및 패닝. +* **처리 로직:** `store/useViewStore.ts` 업데이트 및 `lib/math/` 행렬 변환(Matrix Transformation). +* **우선순위:** **SHOULD** + +## 3.2 비기능 요구사항 (NFR) +* **성능:** 10,000bp 데이터 기준 렌더링 속도 60fps 유지. +* **가용성:** 로컬 및 Vercel 배포 환경 상시 접근. +* **호환성:** HTML5 Canvas API 지원 최신 브라우저 (Chrome, Firefox, Safari, Edge). +* **접근성:** TBD (별도 고려 필요). \ No newline at end of file diff --git a/docs/spec_scenario&UI.md b/docs/spec_scenario&UI.md new file mode 100644 index 0000000..4d89898 --- /dev/null +++ b/docs/spec_scenario&UI.md @@ -0,0 +1,32 @@ +# 4. 유저 플로우 (User Flow) + +## 4.1 정상 시나리오 +1. **입력:** 사용자가 메인 대시보드에서 FASTA 서열 입력/업로드. +2. **파싱:** 프론트가 서열 길이(bp) 및 기본 정보 표시. +3. **요청:** 파라미터 설정 후 "프라이머 설계" 실행. +4. **수신:** 백엔드 API로부터 후보 목록 및 좌표 수신. +5. **렌더링:** 캔버스가 뷰포트 기반 렌더링 및 Auto Layout 적용. +6. **탐색/선택:** 줌/팬으로 탐색, 후보 클릭하여 상세 정보 확인. +7. **내보내기:** 필터/정렬 후 결과 내보내기. + +## 4.2 실패 시나리오 +* **FASTA 오류:** 허용되지 않는 문자 포함 시 즉시 에러 메시지 표시. +* **네트워크 오류:** 백엔드 연결 실패 시 "재시도" 버튼 제공. + +--- + +# 6. UI 규칙 (UI Rules) + +## 6.1 화면 구성 +* **메인 대시보드:** 서열 입력, 설계 실행, 결과 패널, 캔버스 뷰. +* **캔버스 컨트롤:** 줌 인/아웃, 리셋 뷰. +* **패널:** 후보 리스트, 상세 정보. + +## 6.2 주요 메시지 및 규칙 +* **서열 입력 검증:** + * 허용 문자: **A, C, G, T, N** (TBD: IUPAC 확장 허용 여부 확인 필요) + * 에러 문구: “허용되지 않는 문자가 포함되어 있습니다: {char}” +* **설계 실행 상태:** + * 로딩: “프라이머 후보를 생성 중입니다…” + 스피너 + * 실패: “설계 요청에 실패했습니다. 다시 시도해 주세요.” + * 빈 상태(0건): “조건에 맞는 프라이머 후보가 없습니다.” \ No newline at end of file diff --git a/main.py b/main.py index daf30f2..8a98bb4 100644 --- a/main.py +++ b/main.py @@ -1,2 +1,7 @@ from fastapi import FastAPI +from api.v1.endpoints.health import router as health_router + +app = FastAPI(title="PrimerFlow API", version="0.1.0") + +app.include_router(health_router) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..37366ec --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1163 @@ +{ + "name": "PrimerFlow-BE", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@commitlint/cli": "^20.3.0", + "@commitlint/config-conventional": "^20.3.0" + }, + "devDependencies": { + "husky": "^9.1.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@commitlint/cli": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.3.0.tgz", + "integrity": "sha512-HXO8YVfqdBK+MnlX2zqNrv6waGYPs6Ysjm5W2Y0GMagWXwiIKx7C8dcIX9ca+QdHq4WA0lcMnZLQ0pzQh1piZg==", + "license": "MIT", + "dependencies": { + "@commitlint/format": "^20.2.0", + "@commitlint/lint": "^20.3.0", + "@commitlint/load": "^20.3.0", + "@commitlint/read": "^20.2.0", + "@commitlint/types": "^20.2.0", + "tinyexec": "^1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.3.0.tgz", + "integrity": "sha512-g1OXVl6E2v0xF1Ru2RpxQ+Vfy7XUcUsCmLKzGUrhFLS4hSNykje0QSy6djBtzOiOBQCepBrmIlqx/gRlzrSh5A==", + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.2.0", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.2.0.tgz", + "integrity": "sha512-SQCBGsL9MFk8utWNSthdxd9iOD1pIVZSHxGBwYIGfd67RTjxqzFOSAYeQVXOu3IxRC3YrTOH37ThnTLjUlyF2w==", + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.2.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/ensure": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.2.0.tgz", + "integrity": "sha512-+8TgIGv89rOWyt3eC6lcR1H7hqChAKkpawytlq9P1i/HYugFRVqgoKJ8dhd89fMnlrQTLjA5E97/4sF09QwdoA==", + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", + "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.2.0.tgz", + "integrity": "sha512-PhNoLNhxpfIBlW/i90uZ3yG3hwSSYx7n4d9Yc+2FAorAHS0D9btYRK4ZZXX+Gm3W5tDtu911ow/eWRfcRVgNWg==", + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.2.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.2.0.tgz", + "integrity": "sha512-Lz0OGeZCo/QHUDLx5LmZc0EocwanneYJUM8z0bfWexArk62HKMLfLIodwXuKTO5y0s6ddXaTexrYHs7v96EOmw==", + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.2.0", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.3.0.tgz", + "integrity": "sha512-X19HOGU5nRo6i9DIY0kG0mhgtvpn1UGO1D6aLX1ILLyeqSM5yJyMcrRqNj8SLgeSeUDODhLY9QYsBIG0LdNHkA==", + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^20.2.0", + "@commitlint/parse": "^20.2.0", + "@commitlint/rules": "^20.3.0", + "@commitlint/types": "^20.2.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.3.0.tgz", + "integrity": "sha512-amkdVZTXp5R65bsRXRSCwoNXbJHR2aAIY/RGFkoyd63t8UEwqEgT3f0MgeLqYw4hwXyq+TYXKdaW133E29pnGQ==", + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^20.2.0", + "@commitlint/execute-rule": "^20.0.0", + "@commitlint/resolve-extends": "^20.2.0", + "@commitlint/types": "^20.2.0", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/message": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.0.0.tgz", + "integrity": "sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ==", + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.2.0.tgz", + "integrity": "sha512-LXStagGU1ivh07X7sM+hnEr4BvzFYn1iBJ6DRg2QsIN8lBfSzyvkUcVCDwok9Ia4PWiEgei5HQjju6xfJ1YaSQ==", + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.2.0", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.2.0.tgz", + "integrity": "sha512-+SjF9mxm5JCbe+8grOpXCXMMRzAnE0WWijhhtasdrpJoAFJYd5UgRTj/oCq5W3HJTwbvTOsijEJ0SUGImECD7Q==", + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^20.0.0", + "@commitlint/types": "^20.2.0", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.2.0.tgz", + "integrity": "sha512-KVoLDi9BEuqeq+G0wRABn4azLRiCC22/YHR2aCquwx6bzCHAIN8hMt3Nuf1VFxq/c8ai6s8qBxE8+ZD4HeFTlQ==", + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^20.2.0", + "@commitlint/types": "^20.2.0", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules": { + "version": "20.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.3.0.tgz", + "integrity": "sha512-TGgXN/qBEhbzVD13crE1l7YSMJRrbPbUL0OBZALbUM5ER36RZmiZRu2ud2W/AA7HO9YLBRbyx6YVi2t/2Be0yQ==", + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^20.2.0", + "@commitlint/message": "^20.0.0", + "@commitlint/to-lines": "^20.0.0", + "@commitlint/types": "^20.2.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-20.0.0.tgz", + "integrity": "sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==", + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.0.0.tgz", + "integrity": "sha512-drXaPSP2EcopukrUXvUXmsQMu3Ey/FuJDc/5oiW4heoCfoE5BdLQyuc7veGeE3aoQaTVqZnh4D5WTWe2vefYKg==", + "license": "MIT", + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.2.0.tgz", + "integrity": "sha512-KTy0OqRDLR5y/zZMnizyx09z/rPlPC/zKhYgH8o/q6PuAjoQAKlRfY4zzv0M64yybQ//6//4H1n14pxaLZfUnA==", + "license": "MIT", + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.2.tgz", + "integrity": "sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "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==", + "license": "MIT", + "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/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "license": "Python-2.0" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "license": "MIT", + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", + "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "license": "MIT", + "dependencies": { + "jiti": "^2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "license": "MIT", + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "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==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "license": "MIT", + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "license": "MIT" + }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "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/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "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==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "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==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..12865c4 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "devDependencies": { + "husky": "^9.1.7" + }, + "dependencies": { + "@commitlint/cli": "^20.3.0", + "@commitlint/config-conventional": "^20.3.0" + } +}