From 29d349ed1e24d33267cdd09fd31d2c7608910e3d Mon Sep 17 00:00:00 2001 From: manNomi Date: Mon, 26 Jan 2026 01:05:38 +0900 Subject: [PATCH 01/10] feat: add multi-university support with homeUniversityName MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add HomeUniversity enum (인하대학교, 인천대학교, 성신여자대학교) - Add HomeUniversitySlug type and slug mappings (inha, incheon, sungshin) - Create university selection onboarding page at /university - Add [homeUniversity] dynamic routes for filtered university lists - Add [homeUniversity]/[id] detail page with context-aware navigation - Add [homeUniversity]/search page with filters - Add backHref prop to TopDetailNavigation component - Add linkPrefix prop to UniversityCard and UniversityCards components - ISR enabled with 1 hour revalidation --- .../(home)/_ui/HomeUniversityCard.tsx | 63 +++++ apps/web/src/app/university/(home)/layout.tsx | 18 ++ apps/web/src/app/university/(home)/page.tsx | 35 +++ .../university/[homeUniversity]/[id]/page.tsx | 160 +++++++++++++ .../[homeUniversity]/_ui/RegionFilter.tsx | 42 ++++ .../[homeUniversity]/_ui/SearchBar.tsx | 65 +++++ .../_ui/UniversityListContent.tsx | 74 ++++++ .../app/university/[homeUniversity]/page.tsx | 74 ++++++ .../search/_ui/SearchPageContent.tsx | 225 ++++++++++++++++++ .../[homeUniversity]/search/page.tsx | 64 +++++ apps/web/src/app/university/page.tsx | 63 ++--- .../components/layout/TopDetailNavigation.tsx | 11 +- .../components/ui/UniverSityCard/index.tsx | 10 +- .../university/UniversityCards/index.tsx | 5 +- apps/web/src/constants/university.ts | 78 +++++- apps/web/src/types/university.ts | 54 +---- 16 files changed, 940 insertions(+), 101 deletions(-) create mode 100644 apps/web/src/app/university/(home)/_ui/HomeUniversityCard.tsx create mode 100644 apps/web/src/app/university/(home)/layout.tsx create mode 100644 apps/web/src/app/university/(home)/page.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/[id]/page.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/_ui/RegionFilter.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/_ui/SearchBar.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/_ui/UniversityListContent.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/page.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/search/_ui/SearchPageContent.tsx create mode 100644 apps/web/src/app/university/[homeUniversity]/search/page.tsx diff --git a/apps/web/src/app/university/(home)/_ui/HomeUniversityCard.tsx b/apps/web/src/app/university/(home)/_ui/HomeUniversityCard.tsx new file mode 100644 index 00000000..5c37567d --- /dev/null +++ b/apps/web/src/app/university/(home)/_ui/HomeUniversityCard.tsx @@ -0,0 +1,63 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; + +import type { HomeUniversityInfo } from "@/constants/university"; + +interface HomeUniversityCardProps { + university: HomeUniversityInfo; +} + +const HomeUniversityCard = ({ university }: HomeUniversityCardProps) => { + return ( + +
+ {`${university.name} { + // 이미지 로드 실패 시 기본 텍스트 표시 + const target = e.target as HTMLImageElement; + target.style.display = "none"; + }} + /> +
+ +
+ {university.name} + {university.description} +
+ +
+ + + +
+ + ); +}; + +export default HomeUniversityCard; diff --git a/apps/web/src/app/university/(home)/layout.tsx b/apps/web/src/app/university/(home)/layout.tsx new file mode 100644 index 00000000..26d3e9d7 --- /dev/null +++ b/apps/web/src/app/university/(home)/layout.tsx @@ -0,0 +1,18 @@ +import type { ReactNode } from "react"; + +import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; + +interface LayoutProps { + children: ReactNode; +} + +const UniversityHomeLayout = ({ children }: LayoutProps) => { + return ( + <> + + {children} + + ); +}; + +export default UniversityHomeLayout; diff --git a/apps/web/src/app/university/(home)/page.tsx b/apps/web/src/app/university/(home)/page.tsx new file mode 100644 index 00000000..3b0fff91 --- /dev/null +++ b/apps/web/src/app/university/(home)/page.tsx @@ -0,0 +1,35 @@ +import type { Metadata } from "next"; + +import { HOME_UNIVERSITY_LIST } from "@/constants/university"; + +import HomeUniversityCard from "./_ui/HomeUniversityCard"; + +export const revalidate = 3600; // 1시간마다 재검증 (ISR) + +export const metadata: Metadata = { + title: "대학 선택 | 솔리드커넥션", + description: "소속 대학교를 선택하여 교환학생 정보를 확인하세요.", +}; + +const UniversitySelectPage = () => { + return ( +
+
+

소속 대학교 선택

+

+ 소속 대학교를 선택하면 +
+ 해당 대학의 교환학생 정보를 확인할 수 있습니다. +

+
+ +
+ {HOME_UNIVERSITY_LIST.map((university) => ( + + ))} +
+
+ ); +}; + +export default UniversitySelectPage; diff --git a/apps/web/src/app/university/[homeUniversity]/[id]/page.tsx b/apps/web/src/app/university/[homeUniversity]/[id]/page.tsx new file mode 100644 index 00000000..9d3bd20c --- /dev/null +++ b/apps/web/src/app/university/[homeUniversity]/[id]/page.tsx @@ -0,0 +1,160 @@ +import type { Metadata } from "next"; +import { notFound } from "next/navigation"; + +import { getAllUniversities, getUniversityDetail } from "@/apis/universities/server"; +import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; +import { getHomeUniversityBySlug, HOME_UNIVERSITY_SLUGS } from "@/constants/university"; +import type { HomeUniversitySlug } from "@/types/university"; + +// 기존 UniversityDetail 컴포넌트 재사용 +import UniversityDetail from "../../[id]/_ui/UniversityDetail"; + +export const revalidate = false; // 완전 정적 생성 + +// 모든 homeUniversity + id 조합에 대해 정적 경로 생성 +export async function generateStaticParams() { + const universities = await getAllUniversities(); + + const params: { homeUniversity: string; id: string }[] = []; + + // 각 대학에 대해 모든 homeUniversity 슬러그와 조합 + for (const slug of HOME_UNIVERSITY_SLUGS) { + const homeUniversityInfo = getHomeUniversityBySlug(slug); + if (!homeUniversityInfo) continue; + + // 해당 홈대학에 속하는 대학들만 필터링 + const filteredUniversities = universities.filter((uni) => uni.homeUniversityName === homeUniversityInfo.name); + + for (const university of filteredUniversities) { + params.push({ + homeUniversity: slug, + id: String(university.id), + }); + } + } + + return params; +} + +type PageProps = { + params: Promise<{ homeUniversity: string; id: string }>; +}; + +export async function generateMetadata({ params }: PageProps): Promise { + const { homeUniversity, id } = await params; + + // 유효한 슬러그인지 확인 + if (!HOME_UNIVERSITY_SLUGS.includes(homeUniversity as HomeUniversitySlug)) { + return { title: "파견 학교 상세" }; + } + + const universityData = await getUniversityDetail(Number(id)); + + if (!universityData) { + return { title: "파견 학교 상세" }; + } + + const homeUniversityInfo = getHomeUniversityBySlug(homeUniversity); + const convertedKoreanName = + universityData.term !== process.env.NEXT_PUBLIC_CURRENT_TERM + ? `${universityData.koreanName}(${universityData.term})` + : universityData.koreanName; + + const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com"; + const pageUrl = `${baseUrl}/university/${homeUniversity}/${id}`; + const imageUrl = universityData.backgroundImageUrl + ? universityData.backgroundImageUrl.startsWith("http") + ? universityData.backgroundImageUrl + : `${baseUrl}${universityData.backgroundImageUrl}` + : `${baseUrl}/images/article-thumb.png`; + + const countryExchangeKeyword = `${universityData.country} 교환학생`; + const description = `${convertedKoreanName}(${universityData.englishName}) ${countryExchangeKeyword} 프로그램. 모집인원 ${universityData.studentCapacity}명. ${homeUniversityInfo?.shortName || ""} 학생을 위한 교환학생 정보.`; + const title = `${convertedKoreanName} - ${countryExchangeKeyword} 정보 | 솔리드커넥션`; + + return { + title, + description, + openGraph: { + title, + description, + url: pageUrl, + siteName: "솔리드커넥션", + images: [ + { + url: imageUrl, + width: 1200, + height: 630, + alt: `${convertedKoreanName} 대학 이미지`, + }, + ], + locale: "ko_KR", + type: "website", + }, + twitter: { + card: "summary_large_image", + title, + description, + images: [imageUrl], + }, + alternates: { + canonical: pageUrl, + }, + }; +} + +const CollegeDetailPage = async ({ params }: PageProps) => { + const { homeUniversity, id } = await params; + + // 유효한 슬러그인지 확인 + if (!HOME_UNIVERSITY_SLUGS.includes(homeUniversity as HomeUniversitySlug)) { + notFound(); + } + + const homeUniversityInfo = getHomeUniversityBySlug(homeUniversity); + if (!homeUniversityInfo) { + notFound(); + } + + const collegeId = Number(id); + const universityData = await getUniversityDetail(collegeId); + + if (!universityData) { + notFound(); + } + + const convertedKoreanName = + universityData.term !== process.env.NEXT_PUBLIC_CURRENT_TERM + ? `${universityData.koreanName}(${universityData.term})` + : universityData.koreanName; + + const baseUrl = process.env.NEXT_PUBLIC_WEB_URL || "https://solid-connection.com"; + const pageUrl = `${baseUrl}/university/${homeUniversity}/${collegeId}`; + const countryExchangeKeyword = `${universityData.country} 교환학생`; + + const structuredData = { + "@context": "https://schema.org", + "@type": "EducationalOrganization", + name: convertedKoreanName, + alternateName: universityData.englishName, + url: pageUrl, + description: `${convertedKoreanName}(${universityData.englishName}) ${countryExchangeKeyword} 프로그램 정보`, + image: universityData.backgroundImageUrl + ? universityData.backgroundImageUrl.startsWith("http") + ? universityData.backgroundImageUrl + : `${baseUrl}${universityData.backgroundImageUrl}` + : `${baseUrl}/images/article-thumb.png`, + }; + + return ( + <> + + + + EOF + + - name: GitHub Pages 배포 + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs + publish_branch: gh-pages + + - name: 배포 완료 알림 + run: | + echo "✅ API 문서가 GitHub Pages에 배포되었습니다!" + echo "🔗 URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/" diff --git a/packages/bruno-api-typescript/.github/workflows/api-review.yml b/packages/bruno-api-typescript/.github/workflows/api-review.yml new file mode 100644 index 00000000..089644b8 --- /dev/null +++ b/packages/bruno-api-typescript/.github/workflows/api-review.yml @@ -0,0 +1,156 @@ +name: API 변경사항 리뷰 + +on: + pull_request: + paths: + - 'bruno/**' + +jobs: + review: + runs-on: ubuntu-latest + + steps: + - name: 체크아웃 + uses: actions/checkout@v3 + with: + fetch-depth: 0 # 전체 히스토리 + + - name: Node 설정 + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: 의존성 설치 + run: npm install + + - name: 빌드 + run: npm run build + + - name: 이전 버전 OpenAPI 생성 + run: | + # main 브랜치로 체크아웃하여 이전 버전 생성 + git checkout origin/${{ github.base_ref }} -- bruno/ || true + node dist/cli/index.js generate -i ./bruno -o ./openapi-old.json + + - name: 현재 PR의 Bruno로 복원 + run: | + git checkout ${{ github.head_ref }} -- bruno/ || true + git checkout HEAD -- bruno/ + + - name: 현재 버전 OpenAPI 생성 및 변경사항 감지 + run: | + node dist/cli/index.js generate \ + -i ./bruno \ + -o ./openapi-new.json \ + --title "우리팀 API" \ + --version "1.0.0" + + # 변경사항 감지 + if [ -f openapi-old.json ]; then + cp openapi-old.json openapi-new.json.old + node dist/cli/index.js generate \ + -i ./bruno \ + -o ./openapi-new.json \ + --diff \ + --changelog ./CHANGELOG.md \ + --changelog-format markdown + fi + + - name: Breaking Changes 확인 + id: breaking + run: | + if [ -f CHANGELOG.md ]; then + if grep -q "⚠️ Breaking Changes" CHANGELOG.md || grep -q "Breaking Changes" CHANGELOG.md; then + echo "has_breaking=true" >> $GITHUB_OUTPUT + echo "⚠️ Breaking changes 발견!" + else + echo "has_breaking=false" >> $GITHUB_OUTPUT + echo "✅ Breaking changes 없음" + fi + else + echo "has_breaking=false" >> $GITHUB_OUTPUT + fi + + - name: Bruno 파일 변경사항 확인 + id: bruno_changes + run: | + # 변경된 .bru 파일 목록 + CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep '\.bru$' || echo "") + + if [ -n "$CHANGED_FILES" ]; then + echo "changed_files<> $GITHUB_OUTPUT + echo "$CHANGED_FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + else + echo "changed_files=" >> $GITHUB_OUTPUT + fi + + - name: PR에 변경사항 코멘트 + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + + let comment = '## 🔄 API 변경사항\n\n'; + + // Breaking changes 경고 + const hasBreaking = '${{ steps.breaking.outputs.has_breaking }}' === 'true'; + if (hasBreaking) { + comment += '### ⚠️ **Breaking Changes 발견!**\n\n'; + comment += '> 기존 코드를 깨뜨릴 수 있는 변경사항이 있습니다. 프론트엔드 팀과 상의 후 머지해주세요.\n\n'; + } + + // 변경된 Bruno 파일 목록 + const changedFiles = `${{ steps.bruno_changes.outputs.changed_files }}`; + if (changedFiles) { + comment += '### 📝 변경된 Bruno 파일\n\n'; + comment += '```\n' + changedFiles + '\n```\n\n'; + } + + // Changelog 내용 + if (fs.existsSync('CHANGELOG.md')) { + const changelog = fs.readFileSync('CHANGELOG.md', 'utf8'); + comment += '### 📊 상세 변경사항\n\n'; + comment += changelog; + } else { + comment += '### ✨ 새로운 API가 추가되었습니다!\n\n'; + comment += '변경사항을 확인하려면 Bruno 파일을 참조하세요.\n'; + } + + // API 문서 링크 (배포 후) + comment += '\n---\n\n'; + comment += '### 🔗 유용한 링크\n\n'; + comment += '- 📖 [API 명세서 보기](https://' + context.repo.owner + '.github.io/' + context.repo.repo + '/api-viewer.html)\n'; + comment += '- 🔄 [변경사항 시각화](https://' + context.repo.owner + '.github.io/' + context.repo.repo + '/changelog.html)\n'; + comment += '- 📥 [OpenAPI 다운로드](https://' + context.repo.owner + '.github.io/' + context.repo.repo + '/openapi.json)\n'; + + // PR에 코멘트 작성 + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + + - name: Breaking이 있으면 리뷰 요청 + if: steps.breaking.outputs.has_breaking == 'true' + uses: actions/github-script@v6 + with: + script: | + // Breaking이 있으면 특정 팀원에게 리뷰 요청 + // 필요시 팀원 username으로 변경 + await github.rest.pulls.requestReviewers({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + reviewers: [], // 예: ['frontend-lead', 'tech-lead'] + }); + + - name: 체크 상태 설정 + if: steps.breaking.outputs.has_breaking == 'true' + run: | + echo "⚠️ Breaking changes가 감지되었습니다." + echo "프론트엔드 팀의 승인 후 머지해주세요." + # exit 1을 주석 처리하여 PR을 차단하지 않음 + # 팀 정책에 따라 주석 해제 가능 + # exit 1 diff --git a/packages/bruno-api-typescript/.github/workflows/bruno-repo-notify-frontend.yml.template b/packages/bruno-api-typescript/.github/workflows/bruno-repo-notify-frontend.yml.template new file mode 100644 index 00000000..cd5430fe --- /dev/null +++ b/packages/bruno-api-typescript/.github/workflows/bruno-repo-notify-frontend.yml.template @@ -0,0 +1,49 @@ +# Bruno 저장소용 Workflow +# 이 파일을 Bruno 저장소의 .github/workflows/ 폴더에 복사하세요 + +name: Notify Frontend on Bruno Changes + +on: + push: + branches: + - main + paths: + - 'bruno/**' + +jobs: + notify: + runs-on: ubuntu-latest + + steps: + - name: Checkout Bruno Repository + uses: actions/checkout@v3 + + - name: Repository Dispatch to Frontend + run: | + curl -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.FRONTEND_REPO_TOKEN }}" \ + https://api.github.com/repos/YOUR-ORG/FRONTEND-REPO/dispatches \ + -d '{ + "event_type": "bruno_updated", + "client_payload": { + "bruno_repo": "${{ github.repository }}", + "commit_sha": "${{ github.sha }}", + "commit_message": "${{ github.event.head_commit.message }}", + "author": "${{ github.event.head_commit.author.name }}", + "timestamp": "${{ github.event.head_commit.timestamp }}" + } + }' + + - name: Notify Complete + run: | + echo "✅ Frontend repository has been notified!" + echo "🔗 Check Actions: https://github.com/YOUR-ORG/FRONTEND-REPO/actions" + echo "" + echo "📝 Commit: ${{ github.event.head_commit.message }}" + echo "👤 Author: ${{ github.event.head_commit.author.name }}" + +# 설정 방법: +# 1. YOUR-ORG/FRONTEND-REPO를 실제 프론트엔드 저장소 경로로 변경 +# 2. Bruno 저장소 Settings → Secrets → FRONTEND_REPO_TOKEN 추가 +# (GitHub Personal Access Token with repo, workflow permissions) diff --git a/packages/bruno-api-typescript/.github/workflows/frontend-sync-bruno.yml.template b/packages/bruno-api-typescript/.github/workflows/frontend-sync-bruno.yml.template new file mode 100644 index 00000000..64f98b8d --- /dev/null +++ b/packages/bruno-api-typescript/.github/workflows/frontend-sync-bruno.yml.template @@ -0,0 +1,210 @@ +# 프론트엔드 저장소용 Workflow +# 이 파일을 프론트엔드 저장소의 .github/workflows/ 폴더에 복사하세요 + +name: Sync Bruno API Changes + +on: + repository_dispatch: + types: [bruno_updated] + workflow_dispatch: + inputs: + bruno_repo: + description: 'Bruno Repository (org/repo)' + required: false + default: 'YOUR-ORG/BRUNO-REPO' + +jobs: + sync: + runs-on: ubuntu-latest + + steps: + - name: Checkout Frontend Repository + uses: actions/checkout@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Get Bruno Repository Info + id: bruno_info + run: | + if [ "${{ github.event_name }}" = "repository_dispatch" ]; then + echo "repo=${{ github.event.client_payload.bruno_repo }}" >> $GITHUB_OUTPUT + echo "sha=${{ github.event.client_payload.commit_sha }}" >> $GITHUB_OUTPUT + echo "message=${{ github.event.client_payload.commit_message }}" >> $GITHUB_OUTPUT + else + echo "repo=${{ github.event.inputs.bruno_repo }}" >> $GITHUB_OUTPUT + echo "sha=main" >> $GITHUB_OUTPUT + echo "message=Manual sync" >> $GITHUB_OUTPUT + fi + + - name: Clone Bruno Repository + run: | + echo "📥 Cloning Bruno repository: ${{ steps.bruno_info.outputs.repo }}" + git clone https://github.com/${{ steps.bruno_info.outputs.repo }}.git /tmp/bruno + cd /tmp/bruno + git checkout ${{ steps.bruno_info.outputs.sha }} || git checkout main + echo "✅ Bruno repository cloned successfully" + + - name: Install Dependencies + run: npm install + + - name: Generate OpenAPI and Detect Changes + run: | + echo "🔄 Generating OpenAPI spec..." + + # 이전 버전 백업 (변경사항 감지용) + if [ -f public/openapi.json ]; then + cp public/openapi.json public/openapi.json.old + fi + + # OpenAPI 생성 + npx bruno-sync generate \ + -i /tmp/bruno/bruno \ + -o ./public/openapi.json \ + --title "우리팀 API" \ + --version "1.0.0" + + # 변경사항 감지 + if [ -f public/openapi.json.old ]; then + echo "🔍 Detecting changes..." + cp public/openapi.json.old public/openapi.json.old.bak + npx bruno-sync generate \ + -i /tmp/bruno/bruno \ + -o ./public/openapi.json \ + --diff \ + --changelog ./public/CHANGELOG.md \ + --changelog-format markdown + + # HTML Changelog도 생성 + npx bruno-sync generate \ + -i /tmp/bruno/bruno \ + -o ./public/openapi.json \ + --diff \ + --changelog ./public/changelog.html \ + --changelog-format html + + echo "✅ Changes detected and documented" + else + echo "ℹ️ No previous version found, skipping diff" + fi + + - name: Check for Changes + id: changes + run: | + git add public/ + if git diff --staged --quiet; then + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "ℹ️ No changes detected" + else + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "✅ Changes detected!" + + # Breaking changes 확인 + if [ -f public/CHANGELOG.md ]; then + if grep -q "Breaking Changes" public/CHANGELOG.md; then + echo "has_breaking=true" >> $GITHUB_OUTPUT + echo "⚠️ Breaking changes detected!" + else + echo "has_breaking=false" >> $GITHUB_OUTPUT + fi + fi + fi + + - name: Create Pull Request + if: steps.changes.outputs.has_changes == 'true' + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: | + chore: sync API spec from Bruno + + Bruno Repository: ${{ steps.bruno_info.outputs.repo }} + Commit: ${{ steps.bruno_info.outputs.sha }} + Message: ${{ steps.bruno_info.outputs.message }} + branch: api-sync-${{ steps.bruno_info.outputs.sha }} + delete-branch: true + title: "🔄 API 변경사항 동기화 (${{ steps.bruno_info.outputs.sha }})" + body: | + ## 🔄 Bruno API 변경사항 자동 동기화 + + **Bruno Repository**: [`${{ steps.bruno_info.outputs.repo }}`](https://github.com/${{ steps.bruno_info.outputs.repo }}) + **Commit**: `${{ steps.bruno_info.outputs.sha }}` + **Author**: ${{ github.event.client_payload.author || 'N/A' }} + **Message**: + ``` + ${{ steps.bruno_info.outputs.message }} + ``` + + --- + + ### 📊 변경사항 요약 + + ${{ steps.changes.outputs.has_breaking == 'true' && '### ⚠️ **Breaking Changes 발견!**\n\n> 기존 코드를 깨뜨릴 수 있는 변경사항이 있습니다. 주의 깊게 리뷰해주세요.\n\n' || '' }} + + 상세 변경사항은 아래 파일들을 확인하세요: + - 📄 [OpenAPI Spec](../blob/${{ github.ref_name }}/public/openapi.json) + - 📝 [Changelog (Markdown)](../blob/${{ github.ref_name }}/public/CHANGELOG.md) + - 🎨 [Changelog (HTML)](../blob/${{ github.ref_name }}/public/changelog.html) + + --- + + ### ✅ 리뷰 체크리스트 + + - [ ] Breaking changes 확인 및 대응 방안 수립 + - [ ] 영향받는 프론트엔드 코드 파악 + - [ ] Swagger UI에서 새 API 스펙 확인 + - [ ] 타입 에러 없는지 확인 (`npm run build`) + - [ ] 테스트 통과 확인 (`npm run test`) + + --- + + ### 🔗 유용한 링크 + + - 🌐 [Swagger UI로 보기](https://your-org.github.io/your-repo/api-viewer.html) + - 📊 [변경사항 대시보드](https://your-org.github.io/your-repo/changelog.html) + - 📚 [Bruno 저장소](https://github.com/${{ steps.bruno_info.outputs.repo }}) + + --- + + 🤖 이 PR은 자동으로 생성되었습니다. + labels: | + api-sync + autogenerated + ${{ steps.changes.outputs.has_breaking == 'true' && 'breaking-change' || '' }} + + - name: Summary + if: steps.changes.outputs.has_changes == 'true' + run: | + echo "## 🎉 API 동기화 완료!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### 📝 정보" >> $GITHUB_STEP_SUMMARY + echo "- **Bruno Commit**: \`${{ steps.bruno_info.outputs.sha }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Message**: ${{ steps.bruno_info.outputs.message }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.changes.outputs.has_breaking }}" = "true" ]; then + echo "### ⚠️ Breaking Changes" >> $GITHUB_STEP_SUMMARY + echo "Breaking changes가 감지되었습니다. PR을 주의깊게 리뷰해주세요." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + echo "### 🔗 다음 단계" >> $GITHUB_STEP_SUMMARY + echo "1. [Pull Requests](../../pulls)에서 자동 생성된 PR 확인" >> $GITHUB_STEP_SUMMARY + echo "2. Changelog 확인" >> $GITHUB_STEP_SUMMARY + echo "3. 코드 리뷰 및 머지" >> $GITHUB_STEP_SUMMARY + + - name: No Changes + if: steps.changes.outputs.has_changes == 'false' + run: | + echo "ℹ️ 변경사항이 없습니다." + echo "Bruno repository가 업데이트되었지만 OpenAPI 스펙에는 변경이 없습니다." + +# 설정 방법: +# 1. YOUR-ORG/BRUNO-REPO를 실제 Bruno 저장소 경로로 변경 +# 2. public/ 경로를 프로젝트에 맞게 수정 (예: src/api/, docs/ 등) +# 3. Swagger UI 링크를 실제 배포 URL로 변경 diff --git a/packages/bruno-api-typescript/.github/workflows/frontend-workflow.example.yml b/packages/bruno-api-typescript/.github/workflows/frontend-workflow.example.yml new file mode 100644 index 00000000..b19f8747 --- /dev/null +++ b/packages/bruno-api-typescript/.github/workflows/frontend-workflow.example.yml @@ -0,0 +1,87 @@ +name: Update API Hooks (Frontend Repo) + +# 🎯 이 파일은 프론트엔드 리포에 추가하세요 +# Repository Dispatch 이벤트를 받아서 API 훅을 업데이트합니다 + +on: + repository_dispatch: + types: [bruno_updated] + workflow_dispatch: # 수동 실행도 가능 + +jobs: + update-hooks: + runs-on: ubuntu-latest + + steps: + # 프론트엔드 리포 체크아웃 + - name: Checkout Frontend Repo + uses: actions/checkout@v4 + + # Bruno 리포 체크아웃 + - name: Checkout Bruno Repo + uses: actions/checkout@v4 + with: + # ⚠️ 변경 필요: Bruno 리포 경로 + repository: YOUR_USERNAME/YOUR_BRUNO_REPO + path: bruno-repo + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + # bruno-api-typescript 설치 + - name: Install Dependencies + run: | + npm install -D github:manNomi/bruno-api-typescript + + # React Query 훅 생성 + - name: Generate React Query Hooks + run: | + npx bruno-api generate-hooks \ + -i bruno-repo/bruno \ + -o ./src/apis \ + --axios-path "@/utils/axiosInstance" + + # 변경사항 확인 + - name: Check for changes + id: git-check + run: | + if [[ -n $(git status -s) ]]; then + echo "has_changes=true" >> $GITHUB_OUTPUT + else + echo "has_changes=false" >> $GITHUB_OUTPUT + fi + + # 브랜치 생성 및 커밋 + - name: Commit and Push + if: steps.git-check.outputs.has_changes == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + BRANCH_NAME="auto/api-hooks-$(date +%Y%m%d-%H%M%S)" + git checkout -b $BRANCH_NAME + + git add src/apis + git commit -m "chore: update API hooks + + 🤖 Triggered by Bruno repository update + Source SHA: ${{ github.event.client_payload.sha }}" + + git push origin $BRANCH_NAME + + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + id: commit + + # PR 생성 + - name: Create Pull Request + if: steps.git-check.outputs.has_changes == 'true' + run: | + gh pr create \ + --title "🔄 Update API Hooks" \ + --body "Auto-generated from Bruno repository update" \ + --base main \ + --head ${{ steps.commit.outputs.branch_name }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/packages/bruno-api-typescript/.github/workflows/repository-dispatch.example.yml b/packages/bruno-api-typescript/.github/workflows/repository-dispatch.example.yml new file mode 100644 index 00000000..0d7592ff --- /dev/null +++ b/packages/bruno-api-typescript/.github/workflows/repository-dispatch.example.yml @@ -0,0 +1,53 @@ +name: Repository Dispatch Method + +# 🔄 더 모듈화된 방식: Bruno 리포에서 이벤트만 보내고, 프론트엔드 리포에서 처리 +# +# 이 파일: Bruno 리포에 사용 +# 프론트엔드 리포: frontend-workflow.example.yml 사용 + +on: + push: + branches: + - main + paths: + - '**.bru' + +jobs: + trigger-frontend: + runs-on: ubuntu-latest + + steps: + # GitHub App 토큰 생성 + - name: Generate GitHub App Token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + # ⚠️ 변경 필요 + owner: YOUR_GITHUB_USERNAME + repositories: "YOUR_FRONTEND_REPO" + + # Repository Dispatch 이벤트 전송 + - name: Trigger Frontend Workflow + run: | + curl -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ steps.generate-token.outputs.token }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/YOUR_USERNAME/YOUR_FRONTEND_REPO/dispatches \ + -d '{ + "event_type": "bruno_updated", + "client_payload": { + "sha": "${{ github.sha }}", + "ref": "${{ github.ref }}", + "repository": "${{ github.repository }}", + "actor": "${{ github.actor }}" + } + }' + + - name: Log + run: | + echo "✅ Frontend workflow triggered successfully" + echo "Repository: YOUR_USERNAME/YOUR_FRONTEND_REPO" + echo "Event: bruno_updated" diff --git a/packages/bruno-api-typescript/.github/workflows/sync-to-frontend.example.yml b/packages/bruno-api-typescript/.github/workflows/sync-to-frontend.example.yml new file mode 100644 index 00000000..3d041160 --- /dev/null +++ b/packages/bruno-api-typescript/.github/workflows/sync-to-frontend.example.yml @@ -0,0 +1,161 @@ +name: Sync API Hooks to Frontend + +# 🔄 Bruno 리포의 .bru 파일이 변경되면 자동으로 프론트엔드 리포에 React Query 훅을 생성하고 PR을 만듭니다 +# +# 사용 전 설정: +# 1. GitHub App 생성 및 설치 (docs/GITHUB-APPS-SETUP.md 참고) +# 2. Secrets 설정: APP_ID, APP_PRIVATE_KEY +# 3. 아래 YOUR_* 부분을 실제 값으로 변경 + +on: + push: + branches: + - main # 또는 master + paths: + - '**.bru' # .bru 파일이 변경될 때만 실행 + workflow_dispatch: # 수동 실행 가능 + +jobs: + generate-and-sync: + runs-on: ubuntu-latest + + steps: + # 1. GitHub App 토큰 생성 + - name: Generate GitHub App Token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + # ⚠️ 변경 필요: 본인의 GitHub 사용자명 또는 조직명 + owner: YOUR_GITHUB_USERNAME + # ⚠️ 변경 필요: Bruno 리포와 프론트엔드 리포 이름 (쉼표로 구분) + repositories: "bruno-repo-name,frontend-repo-name" + + # 2. Bruno 리포 체크아웃 + - name: Checkout Bruno Repo + uses: actions/checkout@v4 + with: + path: bruno-repo + + # 3. 프론트엔드 리포 체크아웃 + - name: Checkout Frontend Repo + uses: actions/checkout@v4 + with: + # ⚠️ 변경 필요: 프론트엔드 리포 경로 (예: manNomi/my-frontend-app) + repository: YOUR_USERNAME/YOUR_FRONTEND_REPO + token: ${{ steps.generate-token.outputs.token }} + path: frontend-repo + + # 4. Node.js 설정 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + # 5. bruno-api-typescript 설치 + - name: Install bruno-api-typescript + run: | + cd frontend-repo + npm install -D github:manNomi/bruno-api-typescript + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + + # 6. React Query 훅 생성 + - name: Generate React Query Hooks + run: | + cd frontend-repo + npx bruno-api generate-hooks \ + -i ../bruno-repo/bruno \ + -o ./src/apis \ + --axios-path "@/utils/axiosInstance" + + # 7. 변경사항 확인 + - name: Check for changes + id: git-check + run: | + cd frontend-repo + if [[ -n $(git status -s) ]]; then + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "✅ Changes detected" + else + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "ℹ️ No changes detected" + fi + + # 8. 브랜치 생성 및 커밋 + - name: Commit and Push Changes + if: steps.git-check.outputs.has_changes == 'true' + run: | + cd frontend-repo + + # Git 설정 + git config user.name "bruno-api-sync-bot[bot]" + git config user.email "bruno-api-sync-bot[bot]@users.noreply.github.com" + + # 브랜치 생성 + BRANCH_NAME="auto/update-api-hooks-$(date +%Y%m%d-%H%M%S)" + git checkout -b $BRANCH_NAME + + # 커밋 + git add src/apis + git commit -m "chore: update API hooks from Bruno + + 🤖 Auto-generated by bruno-api-typescript + + Source: ${{ github.repository }}@${{ github.sha }} + Triggered by: ${{ github.actor }}" + + # 푸시 + git push origin $BRANCH_NAME + + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + id: commit + + # 9. PR 생성 + - name: Create Pull Request + if: steps.git-check.outputs.has_changes == 'true' + working-directory: frontend-repo + run: | + gh pr create \ + --title "🔄 Update API Hooks from Bruno" \ + --body "## 🤖 Auto-generated PR + + React Query 훅이 Bruno API 변경사항을 반영하여 업데이트되었습니다. + + ### 📋 Source Information + - **Repository**: \`${{ github.repository }}\` + - **Commit**: [\`${GITHUB_SHA:0:7}\`](https://github.com/${{ github.repository }}/commit/${{ github.sha }}) + - **Triggered by**: @${{ github.actor }} + + ### 📦 Generated Files + - \`src/apis/**/*.ts\` - React Query hooks + - \`src/apis/queryKeys.ts\` - Query key constants + + ### ✅ Review Checklist + - [ ] Breaking changes 확인 + - [ ] 변경된 API 사용하는 컴포넌트 업데이트 + - [ ] \`npm run type-check\` 실행 + - [ ] 테스트 실행 (\`npm test\`) + + --- + *Generated by [bruno-api-typescript](https://github.com/manNomi/bruno-api-typescript)* + " \ + --base main \ + --head ${{ steps.commit.outputs.branch_name }} \ + --label "auto-generated" \ + --label "api-update" + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + + # 10. 결과 요약 + - name: Summary + run: | + echo "## 🎉 Workflow Completed" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ steps.git-check.outputs.has_changes }}" == "true" ]]; then + echo "✅ PR created successfully!" >> $GITHUB_STEP_SUMMARY + echo "- Branch: \`${{ steps.commit.outputs.branch_name }}\`" >> $GITHUB_STEP_SUMMARY + else + echo "ℹ️ No changes detected. PR not created." >> $GITHUB_STEP_SUMMARY + fi diff --git a/packages/bruno-api-typescript/.gitignore b/packages/bruno-api-typescript/.gitignore new file mode 100644 index 00000000..ba3de2d3 --- /dev/null +++ b/packages/bruno-api-typescript/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +dist/ +*.log +.DS_Store +coverage/ +.env +*.tsbuildinfo +bruno +test-output +.bruno-cache/ \ No newline at end of file diff --git a/packages/bruno-api-typescript/API_DEFINITIONS_SPECIFICATION.md b/packages/bruno-api-typescript/API_DEFINITIONS_SPECIFICATION.md new file mode 100644 index 00000000..e6cbc6fb --- /dev/null +++ b/packages/bruno-api-typescript/API_DEFINITIONS_SPECIFICATION.md @@ -0,0 +1,277 @@ +# API Definitions Specification + +## Overview + +This document describes how Bruno files are transformed into typed API definitions and factory functions for type-safe API consumption in TypeScript applications. + +## Architecture + +### 1. Generated File Structure + +For each domain (based on Bruno folder structure), the following files are generated: + +``` +src/apis/ +├── users/ +│ ├── api.ts # API factory with all endpoints +│ ├── apiDefinitions.ts # Type metadata for each endpoint +│ └── index.ts # Exports +├── products/ +│ ├── api.ts +│ ├── apiDefinitions.ts +│ └── index.ts +``` + +### 2. API Factory (api.ts) + +**Purpose**: Provides typed API client functions grouped by domain. + +**Example**: +```typescript +export const usersApi = { + getProfile: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get(`/users/profile`, { params: params?.params }); + return res.data; + }, + + updateProfile: async (params: { data: UpdateProfileRequest }): Promise => { + const res = await axiosInstance.put(`/users/profile`, params.data); + return res.data; + }, +}; +``` + +**Type Safety Features**: +- Full TypeScript type inference +- Compile-time parameter validation +- Response type checking + +### 3. API Definitions (apiDefinitions.ts) + +**Purpose**: Provides typed metadata about each API endpoint. + +**Example**: +```typescript +import type { GetProfileResponse, UpdateProfileRequest, UpdateProfileResponse } from './api'; + +export const usersApiDefinitions = { + getProfile: { + method: 'GET' as const, + path: '/users/profile' as const, + pathParams: {} as Record, + queryParams: {} as Record, + body: {} as Record, + response: {} as GetProfileResponse, + }, + + updateProfile: { + method: 'PUT' as const, + path: '/users/profile' as const, + pathParams: {} as Record, + queryParams: {} as Record, + body: {} as UpdateProfileRequest, + response: {} as UpdateProfileResponse, + }, +} as const; + +export type UsersApiDefinitions = typeof usersApiDefinitions; +``` + +**Metadata Fields**: + +| Field | Type | Description | +|-------|------|-------------| +| `method` | `'GET' \| 'POST' \| 'PUT' \| 'PATCH' \| 'DELETE'` | HTTP method | +| `path` | `string` | URL path template | +| `pathParams` | Type object | Path parameter types | +| `queryParams` | Type object | Query parameter types | +| `body` | Type object | Request body type | +| `response` | Type object | Response type | + +## Type Generation Rules + +### 1. Path Parameters + +**Bruno File**: `GET /users/:userId/posts/:postId` + +**Generated Type**: +```typescript +pathParams: {} as { userId: string | number; postId: string | number } +``` + +### 2. Query Parameters + +**For GET requests**: +```typescript +queryParams: {} as Record +``` + +**For non-GET requests**: +```typescript +queryParams: {} as Record +``` + +### 3. Request Body + +**For POST/PUT/PATCH with body**: +```typescript +body: {} as CreateUserRequest +``` + +**For GET/DELETE or no body**: +```typescript +body: {} as Record +``` + +### 4. Response Types + +**Generated from Bruno docs block**: +```typescript +response: {} as GetUserResponse +``` + +**If no docs block**: +```typescript +response: {} as void +``` + +## Usage Examples + +### Direct API Calls + +```typescript +import { usersApi } from '@/apis/users'; + +// GET request +const profile = await usersApi.getProfile({ + params: { includeDetails: true } +}); + +// POST request +const newUser = await usersApi.createUser({ + data: { name: 'John', email: 'john@example.com' } +}); + +// PUT request with path params +const updated = await usersApi.updatePost({ + postId: 123, + data: { title: 'New Title' } +}); +``` + +### With Custom Hooks + +```typescript +import { usersApi } from '@/apis/users'; + +export async function fetchProfile() { + return usersApi.getProfile({}); +} +``` + +### Using Type Metadata + +```typescript +import { usersApiDefinitions } from '@/apis/users'; + +// Extract types +type ProfileResponse = typeof usersApiDefinitions.getProfile.response; +type UpdateRequest = typeof usersApiDefinitions.updateProfile.body; + +// Runtime metadata +console.log(usersApiDefinitions.getProfile.method); // 'GET' +console.log(usersApiDefinitions.getProfile.path); // '/users/profile' +``` + +## File Generation Process + +1. **Parse Bruno Files**: Extract API definitions from `.bru` files +2. **Extract Metadata**: Determine method, path, parameters, body, response +3. **Infer Types**: Generate TypeScript types from docs JSON examples +4. **Generate Factory**: Create typed API client functions +5. **Generate Definitions**: Create type metadata exports +6. **Generate Index**: Export all APIs from domain + +## Type Safety Guarantees + +### Compile-Time Validation + +```typescript +// ✅ Correct usage +await usersApi.getProfile({ params: { page: 1 } }); + +// ❌ Type error: missing data parameter +await usersApi.createUser({}); + +// ❌ Type error: wrong parameter type +await usersApi.getProfile({ data: {} }); +``` + +### Response Type Inference + +```typescript +const profile = await usersApi.getProfile({}); +// profile is automatically typed as GetProfileResponse + +profile.id; // ✅ OK +profile.username; // ✅ OK +profile.invalid; // ❌ Type error +``` + +## Best Practices + +### 1. Do Not Modify Generated Files + +Generated files (`api.ts`, `apiDefinitions.ts`) are overwritten on each generation. Do not add custom logic to these files. + +### 2. Keep Custom Logic Separate + +``` +src/ +├── apis/ # Generated (do not modify) +│ └── users/ +│ ├── api.ts +│ └── apiDefinitions.ts +└── hooks/ # Custom hooks (safe to modify) + └── useAuth.ts +``` + +### 3. Use Type Metadata for Generic Functions + +```typescript +import { usersApiDefinitions } from '@/apis/users'; + +function getEndpointPath( + endpoint: T +) { + return usersApiDefinitions[endpoint].path; +} +``` + +## Migration from Query Keys + +Previous version generated hooks and query keys. The new approach: + +**Before**: +```typescript +import { useGetProfile } from '@/apis/users'; +const { data } = useGetProfile(); +``` + +**After**: +```typescript +import { usersApi } from '@/apis/users'; +const data = await usersApi.getProfile({}); +``` + +**Benefits**: +- Framework-agnostic API clients +- Easier testing (mock API functions directly) +- Clear separation between data fetching and business logic + +## Related Files + +- `src/generator/apiFactoryGenerator.ts` - Generates API factory +- `src/generator/apiDefinitionGenerator.ts` - Generates type definitions +- `src/generator/typeGenerator.ts` - Infers TypeScript types +- `src/parser/bruParser.ts` - Parses Bruno files diff --git a/packages/bruno-api-typescript/CHANGELOG.md b/packages/bruno-api-typescript/CHANGELOG.md new file mode 100644 index 00000000..e258f84a --- /dev/null +++ b/packages/bruno-api-typescript/CHANGELOG.md @@ -0,0 +1,166 @@ +# 변경 이력 + +이 프로젝트의 모든 주요 변경사항을 기록합니다. + +형식은 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)를 기반으로 하며, +[Semantic Versioning](https://semver.org/spec/v2.0.0.html)을 따릅니다. + +## [Unreleased] + +### Added + +#### 🎭 MSW (Mock Service Worker) 자동 생성 기능 +- `.bru` 파일에서 MSW 핸들러 자동 생성 +- `--msw-output` 옵션으로 MSW 핸들러 출력 디렉토리 지정 +- 도메인별 MSW 핸들러 그룹화 및 index 파일 자동 생성 +- `meta.done` 필드로 MSW 생성 제어 + - `done: true`: MSW 생성 건너뛰기 (백엔드 완료시) + - `done` 없음 또는 `false`: MSW 핸들러 자동 생성 + +**파일 추가:** +- `src/generator/mswGenerator.ts`: MSW 핸들러 생성 로직 + +**사용 예시:** +```bash +npx bruno-api generate-hooks -i ./bruno -o ./src/apis --msw-output ./src/mocks +``` + +**생성되는 구조:** +``` +src/mocks/ +├── admin/ +│ ├── get-list.ts +│ ├── post-create.ts +│ └── index.ts +├── users/ +│ ├── get-profile.ts +│ └── index.ts +└── handlers.ts +``` + +#### 📁 한글 폴더명 지원 +- Bruno 폴더명에서 `한글명 [EnglishKey]` 형식 지원 +- 대괄호 `[]` 안의 영문 키만 추출하여 파일명 및 도메인으로 사용 +- 한글 폴더명으로 가독성 확보, 영문 키로 코드 생성 + +**예시:** +- `사용자 [admin]/get-list.bru` → 도메인: `admin` +- `지원서 [applications]/create.bru` → 도메인: `applications` +- `상품 [products]/update.bru` → 도메인: `products` + +**파일 수정:** +- `src/generator/index.ts:48-60`: extractDomain() 함수에 `[키]` 추출 로직 추가 +- `src/converter/openapiConverter.ts:131-143`: extractDomain() 함수 수정 +- `src/diff/changeDetector.ts:189-202`: extractDomain() 함수 수정 + +### Changed + +#### 📝 Parser 업데이트 +- `meta` 블록에 `done` 필드 추가 +- `done: true` 파싱 지원 + +**파일 수정:** +- `src/parser/bruParser.ts:27`: ParsedBrunoFile 인터페이스에 `done?: boolean` 추가 +- `src/parser/bruParser.ts:188-191`: parseMeta() 함수에 done 필드 파싱 로직 추가 + +#### 📚 문서 업데이트 +- `docs/bruno-guide.md`: MSW 생성 제어 및 한글 폴더명 사용 가이드 추가 +- `README.md`: MSW 기능 및 한글 폴더명 지원 추가 +- `README.ko.md`: 한국어 문서 업데이트 + +### Technical Details + +#### MSW 생성 로직 +1. `.bru` 파일 파싱 +2. `meta.done` 확인 + - `done: true`면 건너뛰기 + - 그 외의 경우 MSW 핸들러 생성 +3. `docs` 블록에서 JSON 추출 +4. MSW 핸들러 코드 생성 +5. 도메인별 디렉토리에 파일 저장 +6. 도메인별 index.ts 생성 +7. 전체 handlers.ts 생성 + +#### 폴더명 추출 로직 +```typescript +const match = folderName.match(/\[([^\]]+)\]/); +if (match) { + return match[1]; // 대괄호 안의 키만 반환 +} +return folderName; // 대괄호가 없으면 폴더명 그대로 반환 +``` + +## [0.3.0] - 2025-01-XX + +### Previous Features +- Bruno to OpenAPI conversion +- Change detection +- Changelog generation (MD/JSON/HTML) +- Breaking change identification +- CLI tool +- TypeScript type generation +- API client generation +- Typed API client generation + +--- + +## 마이그레이션 가이드 + +### 기존 프로젝트용 + +#### 1. 한글 폴더명 사용 (선택사항) +기존 영문 폴더명을 그대로 사용하거나, 한글 폴더명으로 변경할 수 있습니다. + +**변경 전:** +``` +bruno/ +└── applications/ + └── get-list.bru +``` + +**변경 후:** +``` +bruno/ +└── 지원서 [applications]/ + └── get-list.bru +``` + +생성되는 파일명은 동일합니다: `applications/useGetApplicationsList.ts` + +#### 2. MSW 핸들러 생성 (선택사항) +기존 API 클라이언트 생성에 `--msw-output` 옵션을 추가하면 됩니다. + +**package.json 업데이트:** +```json +{ + "scripts": { + "api:hooks": "bruno-api generate-hooks -i ./bruno -o ./src/apis", + "api:mocks": "bruno-api generate-hooks -i ./bruno -o ./src/apis --msw-output ./src/mocks" + } +} +``` + +#### 3. 백엔드 완료된 API에 done 필드 추가 (선택사항) +이미 백엔드가 완료된 API는 `meta.done: true`를 추가하여 MSW 생성을 건너뛸 수 있습니다. + +**예시:** +```bru +meta { + name: Get User Profile + type: http + seq: 1 + done: true # 백엔드 완료, MSW 불필요 +} +``` + +--- + +## Contributors + +- Claude Code AI Assistant + +## Links + +- [GitHub Repository](https://github.com/manNomi/bruno-api-typescript) +- [Documentation](./docs/) +- [Bruno Guide](./docs/bruno-guide.md) diff --git a/packages/bruno-api-typescript/README.md b/packages/bruno-api-typescript/README.md new file mode 100644 index 00000000..626afb05 --- /dev/null +++ b/packages/bruno-api-typescript/README.md @@ -0,0 +1,107 @@ +# bruno-api-typescript + +> **Bruno 파일을 작성하면, 나머지는 자동으로** + +이 프로젝트는 Bruno `.bru` 파일을 OpenAPI 스펙과 타입 안전한 API 클라이언트로 자동 변환하는 GitHub Apps 기반 자동화 도구입니다. + +백엔드 개발자는 Bruno 파일만 작성하면, GitHub Actions가 자동으로 프론트엔드 저장소에 타입 정의와 API 클라이언트를 생성하고 PR을 만들어줍니다. + +## 작동 방식 + +```mermaid +graph LR + A[백엔드: Bruno 파일 수정] --> B[GitHub Push] + B --> C[GitHub Actions 실행] + C --> D[OpenAPI 생성] + C --> E[API 클라이언트 생성] + E --> F[프론트엔드 저장소 PR 자동 생성] +``` + +## 설정 방법 (5단계) + +### 1단계: 저장소 준비 + +```bash +# Bruno API 저장소 클론 +git clone https://github.com/solid-connection/bruno-api-typescript.git +cd bruno-api-typescript + +# 의존성 설치 및 빌드 +npm install +npm run build +``` + +### 2단계: GitHub App 생성 + +GitHub Settings → Developer settings → GitHub Apps → New GitHub App + +필수 권한: + +- **Contents**: Read & Write +- **Pull requests**: Read & Write +- **Workflows**: Read & Write + +생성 후: + +- **App ID** 복사 +- **Private Key** 다운로드 + +### 3단계: Secrets 설정 + +Bruno 저장소와 프론트엔드 저장소 모두에 Secrets 추가: + +- `APP_ID`: GitHub App ID +- `APP_PRIVATE_KEY`: Private Key 전체 내용 +- `INSTALLATION_ID`: Installation ID + +### 4단계: Workflow 파일 추가 + +`.github/workflows/sync-to-frontend.yml` 파일 생성 (자세한 내용은 [설정 가이드](./docs/github-apps-simple.md) 참조) + +### 5단계: Bruno 파일 작성 및 푸시 + +Bruno 파일 작성 후 푸시하면 자동으로 프론트엔드에 PR 생성! + +## Bruno 파일 작성 예시 + +`````bru +meta { + name: Get User Profile + type: http +} + +get /users/profile + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "id": 1, + "username": "johndoe", + "email": "john@example.com", + "createdAt": "2025-01-01T00:00:00Z" + } + ```` +} +````` + +**핵심**: `docs` 블록에 실제 API 응답 JSON을 작성하면, 이를 기반으로 타입과 스키마가 자동 생성됩니다. + +## 추가 문서 + +- **[사용 방법 가이드](./docs/usage-guide.md)** - CLI 사용법과 프로젝트 통합 방법 +- **[GitHub Apps 설정 가이드](./docs/github-apps-simple.md)** - Workflow 파일 예시 포함 +- **[Bruno 파일 작성 튜토리얼](./docs/bruno-tutorial.md)** - 단계별 따라하기 +- **[Bruno 파일 작성 가이드](./docs/bruno-guide.md)** - 상세 레퍼런스 +- **[변경사항 처리 가이드](./docs/migration-guide.md)** - API 클라이언트 변경사항 처리 방법 + +## 라이선스 + +MIT + +--- + +**v0.3.0** | 문의: hanmw110@naver.com diff --git a/packages/bruno-api-typescript/agents.md b/packages/bruno-api-typescript/agents.md new file mode 100644 index 00000000..698643dc --- /dev/null +++ b/packages/bruno-api-typescript/agents.md @@ -0,0 +1,96 @@ +# Project: bruno-api-typescript + +## Overview + +The `bruno-api-typescript` project is an automation tool designed to streamline API synchronization between backend development (using Bruno `.bru` files) and frontend development. It automatically transforms Bruno request definitions into OpenAPI specifications and typed API clients (along with optional Mock Service Worker (MSW) handlers). This entire process is integrated with GitHub Apps and GitHub Actions, enabling automated generation of client code and Pull Requests in frontend repositories whenever backend API definitions in Bruno files change. + +**Core Goal:** To minimize manual effort in maintaining API client code and documentation by automating the generation process directly from Bruno API definitions. + +## Key Functionalities + +1. **OpenAPI Specification Generation:** Converts Bruno `.bru` collection files into a comprehensive OpenAPI 3.0.0 specification (`openapi.json`). This includes API paths, methods, request bodies, and inferred response schemas based on JSON examples provided in the Bruno `docs` blocks. +2. **Typed API Client Generation:** Generates TypeScript API factory functions from Bruno API definitions. These clients are type-safe, leveraging inferred schemas for request and response types. +3. **API Definitions Generation:** Creates typed metadata files (`apiDefinitions.ts`) that provide type information for each API endpoint including method, path, parameters, body, and response types. +4. **Mock Service Worker (MSW) Handlers Generation (Optional):** Can generate MSW handlers to mock API responses during frontend development and testing, based on the same Bruno definitions. +5. **Change Detection and Changelog Generation:** Detects breaking changes between different versions of the OpenAPI specification and can generate detailed changelogs (Markdown, JSON, HTML) to inform frontend teams about API modifications. +6. **GitHub Apps Integration:** Designed to run within GitHub Actions workflows, leveraging GitHub Apps for programmatic access to repositories (reading Bruno files, creating PRs in frontend repos). +7. **Incremental Generation:** Utilizes a hash-based caching mechanism (`BrunoHashCache`) to intelligently regenerate only the changed API clients, optimizing performance for large projects. + +## Architecture and Module Interaction + +The project follows a CLI-driven, pipeline-like architecture with a clear separation of concerns. + +### Main Components and Their Responsibilities: + +* **CLI (`src/cli/index.ts`)**: + * **Role:** The primary entry point for the tool. It parses command-line arguments (`generate` for OpenAPI, `generate-hooks` for API clients/MSW). + * **Interaction:** Orchestrates the entire process by invoking the appropriate internal modules based on the command and options provided. +* **Parser (`src/parser/bruParser.ts`)**: + * **Role:** Responsible for reading and parsing individual Bruno `.bru` files. It extracts structured data such as request metadata (`meta`), HTTP details (method, URL), headers, request body, and the crucial `docs` block content. + * **Interaction:** Provides the raw, structured representation of Bruno API definitions to the Converter and Generator modules. +* **Converter (`src/converter/openapiConverter.ts`, `src/converter/schemaBuilder.ts`)**: + * **`openapiConverter.ts` Role:** Takes the parsed Bruno data and constructs the OpenAPI Specification. It iterates through Bruno files, extracts domains for tagging, normalizes URLs, and builds operation objects for each API endpoint. + * **`schemaBuilder.ts` Role:** Infers JSON schemas (used in OpenAPI for request/response bodies) from example JSON data extracted from the Bruno `docs` blocks. It handles primitive types, arrays, and objects, marking properties as `required` if present in the example. + * **Interaction:** `bruParser` feeds data to `openapiConverter`, which in turn uses `schemaBuilder` to infer schemas for the OpenAPI spec. +* **Generator (`src/generator/index.ts`, `src/generator/*Generator.ts`)**: + * **`index.ts` Role:** The main orchestrator for generating frontend-specific code. It manages the `BrunoHashCache` for incremental updates, collects Bruno files, and then dispatches to specialized generators. + * **`apiClientGenerator.ts` (implied from `extractApiFunction`) Role:** Extracts API function metadata from parsed Bruno files. + * **`apiFactoryGenerator.ts` Role:** Generates API factory files, grouping related API functions by domain with full type safety. + * **`apiDefinitionGenerator.ts` Role:** Generates typed API metadata files with method, path, parameter, body, and response type information. + * **`mswGenerator.ts` Role:** Generates Mock Service Worker (MSW) request handlers from Bruno API definitions and `docs` examples. + * **`typeGenerator.ts` Role:** Infers TypeScript types from JSON examples in Bruno `docs` blocks. + * **Interaction:** `bruParser` feeds data to `index.ts`, which then uses various `*Generator.ts` modules to produce the final client-side code. `BrunoHashCache` is used throughout to manage regeneration efficiently. +* **Diffing (`src/diff/changeDetector.ts`, `src/diff/changelogGenerator.ts`)**: + * **`changeDetector.ts` Role:** Compares two OpenAPI specifications to identify differences, categorizing them (e.g., breaking changes, non-breaking changes). + * **`changelogGenerator.ts` Role:** Formats the detected changes into a human-readable changelog. + * **Interaction:** Used by the CLI `generate` command when the `--diff` option is enabled, operating on generated OpenAPI specs. + +## API Structure and Conventions + +This project does not define its own external API endpoints. Instead, it processes API definitions provided in Bruno `.bru` files. + +* **Bruno `.bru` Files:** Serve as the source of truth for API definitions. Each `.bru` file typically represents a single API request and includes: + * `meta` block: Defines request name, type, etc. + * HTTP method and URL (e.g., `get /users/profile`). + * `headers` block: HTTP headers. + * `body:json` block: JSON request body content. + * `docs` block: Crucially, this block can contain Markdown, including ````json` code blocks that provide example JSON responses. These examples are used for schema inference. +* **Generated OpenAPI Spec:** Conforms to the OpenAPI 3.0.0 standard, providing a machine-readable API contract. Paths are normalized (e.g., `/users/:id` becomes `/users/{id}`). +* **Generated API Clients:** Domain-based API factories and typed API definitions for each endpoint. +* **Generated MSW Handlers:** Designed to integrate seamlessly with the Mock Service Worker library. + +## Data Flow + +1. **Input:** Bruno `.bru` files (containing API request definitions and JSON examples in `docs` blocks). +2. **Parsing:** `bruParser` reads `.bru` files into structured `ParsedBrunoFile` objects. +3. **Schema Inference:** `schemaBuilder` infers JSON schemas from `docs` JSON examples within the parsed Bruno files. +4. **OpenAPI Generation:** `openapiConverter` uses parsed Bruno data and inferred schemas to build `OpenAPISpec`. +5. **Client Code Generation:** `generator/index.ts` uses parsed Bruno data and inferred schemas (implicitly via other generator modules) to produce: + * API factory functions (`apiFactoryGenerator`) + * API definitions (`apiDefinitionGenerator`) + * MSW handlers (`mswGenerator`) +6. **Output:** `openapi.json`, TypeScript files for API factories, API definitions, and MSW handlers. +7. **Automation Flow (via GitHub Actions):** + * Backend developer pushes changes to Bruno files. + * GitHub Action triggers `bruno-api-typescript` CLI. + * The tool generates updated OpenAPI spec and frontend client code. + * A Pull Request is automatically created against the frontend repository with the generated code. + +## Technologies Used + +* **TypeScript:** Primary development language. +* **Node.js:** Runtime environment. +* **Commander.js:** CLI framework. +* **Bruno:** API client for defining requests. +* **OpenAPI (Swagger):** Standard for API documentation and client generation. +* **Mock Service Worker (MSW):** API mocking library. +* **Mock Service Worker (MSW):** API mocking library. +* **GitHub Apps / GitHub Actions:** For automation and integration with repositories. +* **YAML:** For parsing Bruno files. + +## Development Environment Setup + +1. Clone the repository. +2. Install dependencies: `npm install`. +3. Build the project: `npm run build`. +4. Refer to `README.md` for detailed GitHub App and workflow configuration. diff --git a/packages/bruno-api-typescript/docs/bruno-guide.md b/packages/bruno-api-typescript/docs/bruno-guide.md new file mode 100644 index 00000000..e51f67db --- /dev/null +++ b/packages/bruno-api-typescript/docs/bruno-guide.md @@ -0,0 +1,651 @@ +# Bruno 파일 작성 가이드 (백엔드 개발자용) + +> **핵심**: `docs` 블록에 응답 JSON을 정확히 작성하면 끝입니다. + +## 기본 구조 + +`````bru +meta { + name: API 이름 + type: http +} + +get /api/endpoint + +headers { + Authorization: Bearer {{token}} +} + +body:json { + { + "key": "value" + } +} + +docs { + ````json + { + "id": 1, + "username": "johndoe" + } + ```` +} +````` + +## 필수 작성 규칙 + +### 1. `docs` 블록이 핵심 + +**`docs` 블록이 전부입니다!** 이 블록의 JSON으로 타입과 스키마가 자동 생성됩니다. + +**올바른 예시 (단일 응답):** + +`````bru +docs { + ````json + { + "id": 1, + "username": "johndoe", + "email": "john@example.com", + "createdAt": "2025-01-01T00:00:00Z", + "profile": { + "age": 25, + "city": "Seoul" + }, + "tags": ["developer", "backend"] + } + ```` +} +````` + +**올바른 예시 (상태 코드별 응답):** + +여러 상태 코드를 정의할 수 있지만, **200 OK만 사용**됩니다: + +````bru +docs { + ## 200 OK + ``` + { + "id": 1, + "username": "johndoe", + "email": "john@example.com" + } + ``` + + ## 404 Not Found + ``` + { + "message": "사용자를 찾을 수 없습니다." + } + ``` +} +```` + +**⚠️ 중요**: 현재는 **200 OK 응답만 타입 생성에 사용**됩니다. 다른 상태 코드(404, 500 등)는 문서화 목적으로만 작성할 수 있습니다. + +### 1-1. 200 OK 응답 필수 작성 + +**200 OK 응답이 없으면 타입 생성이 실패합니다!** + +**❌ 잘못된 예시 (200 OK 없음):** + +````bru +docs { + ## 404 Not Found + ``` + { + "message": "사용자를 찾을 수 없습니다." + } + ``` +} +```` + +**✅ 올바른 예시:** + +````bru +docs { + ## 200 OK + ``` + { + "id": 1, + "username": "johndoe" + } + ``` + + ## 404 Not Found + ``` + { + "message": "사용자를 찾을 수 없습니다." + } + ``` +} +```` + +**주의사항:** + +- 200 OK 응답이 여러 개 있으면 **첫 번째만** 사용됩니다 +- 200 OK 응답의 JSON이 실제 응답과 **정확히 일치**해야 합니다 +- 200 OK 응답이 없으면 단일 JSON 코드 블록을 찾지만, 그것도 없으면 타입 생성 실패 + +### 2. JSON 작성 규칙 + +- ✅ **실제 응답과 동일하게** 작성 +- ✅ **모든 필드를 포함** (옵셔널 필드도) +- ✅ **타입이 명확한 값 사용**: + - 문자열: `"hello"` + - 숫자: `123` 또는 `4.5` + - 불린: `true` / `false` + - 배열: `[1, 2, 3]` (최소 1개 요소 포함) + - 객체: `{ "key": "value" }` + - null: `null` +- ✅ **날짜는 ISO 8601 형식**: `"2025-01-01T00:00:00Z"` + +### 3. 자주 하는 실수 + +**❌ 잘못된 예시:** + +`````bru +docs { + ````json + { + id: 1, // 키에 따옴표 없음 + "name": '홍길동' // 작은따옴표 사용 + } + ```` +} +````` + +**❌ 빈 배열:** + +`````bru +docs { + ````json + { + "users": [] // 타입 추론 불가 → any[]로 추론됨 + } + ```` +} +````` + +**⚠️ 주의**: 빈 배열은 `any[]`로 추론되므로, 최소 1개 요소를 포함해야 합니다. + +**❌ null 값으로 인한 타입 오류:** + +null 값이 있으면 해당 필드의 타입이 `null`로 고정되어 실제 사용 시 타입 오류가 발생할 수 있습니다. + +`````bru +docs { + ````json + { + "optionalField": null // null로 추론되어 타입이 null로 고정됨 + } + ```` +} +````` + +**✅ 올바른 예시 (옵셔널 필드 - 배열에서 유니온 타입 생성):** + +배열 응답에서 여러 아이템을 확인하여 유니온 타입을 자동 생성합니다: + +`````bru +docs { + ````json + [ + { + "status": "active", + "data": "hello", + "optionalField": "value" + }, + { + "status": null, + "data": null, + "optionalField": null + } + ] + ```` +} +````` + +**생성되는 타입:** + +```typescript +export interface ResponseItem { + status: "active" | null; + data: "hello" | null; + optionalField: "value" | null; +} +``` + +**✅ 단일 객체에서 옵셔널 필드:** + +단일 객체의 경우 null 값은 `null` 타입으로만 추론됩니다. 옵셔널 필드를 표현하려면 배열로 작성하세요: + +`````bru +docs { + ````json + { + "requiredField": "value", + "optionalField": "example" // 실제 값으로 작성 + } + ```` +} +````` + +**✅ 올바른 예시:** + +`````bru +docs { + ````json + { + "users": [ + { + "id": 1, + "name": "예시" + } + ] + } + ```` +} +````` + +## 파일명 및 폴더명 가이드라인 + +파일명과 폴더명은 생성되는 코드의 구조와 이름에 직접 영향을 미칩니다. 일관된 네이밍을 위해 다음 규칙을 따르세요. + +### 폴더명 규칙 + +폴더명은 생성되는 도메인 디렉토리 이름이 됩니다. + +#### 지원하는 형식 + +1. **`숫자) 한글명 [영문키]` 형식** (권장) + + ``` + 1) 어드민 [Admin]/ → 생성 폴더: Admin + 7) 어드민 [Admin]/ → 생성 폴더: Admin + 8) 사용자 [Users]/ → 생성 폴더: Users + 9) 멘토 [Mentor]/ → 생성 폴더: Mentor + ``` + + - 대괄호 안의 `영문키`만 사용됩니다 + - 숫자와 한글명은 가독성을 위해 사용, 실제 폴더명에는 포함되지 않음 + +2. **`한글명 [영문키]` 형식** (기존 방식, 호환) + + ``` + 지원서 [applications]/ → 생성 폴더: applications + 사용자 [users]/ → 생성 폴더: users + ``` + + - 대괄호 안의 `영문키`만 사용됩니다 + - 기존 프로젝트와 호환됩니다 + +3. **영문 폴더명** (가장 단순) + ``` + applications/ → 생성 폴더: applications + users/ → 생성 폴더: users + ``` + - 패턴이 없으면 폴더명 그대로 사용 + +#### 폴더명 예시 + +| Bruno 폴더명 | 생성되는 폴더 | 설명 | +| ----------------------- | -------------- | --------------------- | +| `1) 어드민 [Admin]` | `Admin` | 대괄호 안의 키만 사용 | +| `7) 어드민 [Admin]` | `Admin` | 숫자는 무시됨 | +| `지원서 [applications]` | `applications` | 대괄호 안의 키만 사용 | +| `users` | `users` | 그대로 사용 | + +### 파일명 규칙 + +**파일명이 API 함수 이름에 직접 사용됩니다!** + +> ⚠️ **중요**: 파일명에 **HTTP 메서드를 포함하지 마세요**. 메서드는 `.bru` 파일 내부의 `get`, `post`, `put`, `patch`, `delete` 블록에서 자동으로 인식됩니다. + +#### 지원하는 형식 + +1. **`한글명 [영문키]` 형식** (권장, 폴더명과 동일한 패턴) + + ``` + 멘토 목록 조회 [mentor-list].bru → mentor-list → mentorList → getMentorList + 사용자 프로필 [user-profile].bru → user-profile → userProfile → getUserProfile + 지원서 생성 [create-application].bru → create-application → createApplication → postCreateApplication + ``` + + - 대괄호 안의 `영문키`만 사용됩니다 + - 한글명은 가독성을 위해 사용, 실제 코드 생성에는 포함되지 않음 + - **HTTP 메서드 prefix는 자동으로 제거됩니다** (예: `delete-account` → `account`) + +2. **영문 파일명** (기존 방식, 호환) + + ``` + competitors.bru → competitors → getCompetitors + user-profile.bru → user-profile → getUserProfile + create-application.bru → create-application → postCreateApplication + ``` + + - 패턴이 없으면 파일명 그대로 사용 + - **HTTP 메서드 prefix는 자동으로 제거됩니다** + +#### 권장 형식 + +**✅ 올바른 예시:** + +``` +멘토 목록 조회 [mentor-list].bru → mentorList → getMentorList +사용자 프로필 [user-profile].bru → userProfile → getUserProfile +지원서 생성 [create-application].bru → createApplication → postCreateApplication +프로필 수정 [update-profile].bru → updateProfile → putUpdateProfile +회원 탈퇴 [account].bru → account → deleteAccount +``` + +**❌ 잘못된 예시 (HTTP 메서드 포함):** + +``` +멘토 목록 조회 [get-mentor-list].bru → getMentorList → getGetMentorList (중복!) +사용자 삭제 [delete-user].bru → deleteUser → deleteDeleteUser (중복!) +``` + +#### 네이밍 규칙 + +1. **kebab-case 사용** (하이픈으로 단어 구분) + + - ✅ `user-profile.bru` + - ❌ `userProfile.bru` (camelCase) + - ❌ `user_profile.bru` (snake_case) + - ❌ `UserProfile.bru` (PascalCase) + +2. **HTTP 메서드 포함하지 않기** (필수) + + - ✅ `account.bru` (DELETE 메서드 → deleteAccount) + - ✅ `sign-up.bru` (POST 메서드 → postSignUp) + - ✅ `mentor-list.bru` (GET 메서드 → getMentorList) + - ❌ `delete-account.bru` (메서드 중복 → deleteDeleteAccount) + - ❌ `post-sign-up.bru` (메서드 중복 → postPostSignUp) + +3. **명확하고 간결한 이름** + + - ✅ `competitors.bru` (명확함) + - ✅ `create-application.bru` (명확함) + - ❌ `api1.bru` (불명확) + - ❌ `test.bru` (불명확) + +4. **한글 파일명 피하기** + - ❌ `멘토 목록 조회.bru` (함수 이름 생성 시 문제 가능) + - ✅ `mentor-list.bru` (영문 사용) + +#### 파일명 예시 + +| Bruno 파일명 | HTTP 메서드 | 추출된 키 | 함수 이름 | +| ---------------------------------- | ----------- | ---------------- | ----------------- | +| `멘토 목록 조회 [mentor-list].bru` | GET | `mentor-list` | `getMentorList` | +| `사용자 프로필 [user-profile].bru` | GET | `user-profile` | `getUserProfile` | +| `지원서 생성 [create].bru` | POST | `create` | `postCreate` | +| `회원 탈퇴 [account].bru` | DELETE | `account` | `deleteAccount` | +| `competitors.bru` | GET | `competitors` | `getCompetitors` | +| `멘토 목록 조회.bru` | GET | `멘토 목록 조회` | `get멘토목록조회` ❌ | + +**핵심**: + +- `한글명 [영문키]` 형식으로 작성하면 한글 설명과 영문 코드를 모두 활용할 수 있습니다 +- 대괄호 안의 영문키만 kebab-case로 작성하면, 자동으로 일관된 API 함수 이름이 생성됩니다! +- **HTTP 메서드는 파일명에 포함하지 마세요** - `.bru` 파일 내부에서 자동으로 인식됩니다! + +### 전체 구조 예시 + +``` +bruno/ +├── 7) 어드민 [Admin]/ # 폴더명: Admin +│ ├── 목록 조회 [list].bru # → adminApi.getList +│ ├── 생성 [create].bru # → adminApi.postCreate +│ └── 수정 [update].bru # → adminApi.putUpdate +├── 지원서 [applications]/ # 폴더명: applications +│ ├── 경쟁자 조회 [competitors].bru # → applicationsApi.getCompetitors +│ ├── 상세 조회 [details].bru # → applicationsApi.getDetails +│ └── 지원서 생성 [create].bru # → applicationsApi.postCreate +├── 사용자 [users]/ # 폴더명: users +│ ├── 프로필 조회 [profile].bru # → usersApi.getProfile +│ └── 프로필 수정 [update-profile].bru # → usersApi.putUpdateProfile +└── bruno.json +``` + +**생성되는 구조:** + +``` +src/apis/ +├── Admin/ +│ ├── api.ts # adminApi 팩토리 +│ ├── apiDefinitions.ts # 타입 정의 +│ └── index.ts +├── applications/ +│ ├── api.ts # applicationsApi 팩토리 +│ ├── apiDefinitions.ts # 타입 정의 +│ └── index.ts +├── users/ +│ ├── api.ts # usersApi 팩토리 +│ ├── apiDefinitions.ts # 타입 정의 +│ └── index.ts +``` + +## 실전 예시 + +### GET - 목록 조회 + +`````bru +meta { + name: Get Competitors + type: http +} + +get /applications/competitors + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "firstChoice": [ + { + "universityId": 1, + "koreanName": "데겐도르프대학", + "studentCapacity": 150, + "applicantCount": 120 + } + ], + "secondChoice": [], + "thirdChoice": [] + } + ```` +} +````` + +### POST - 생성 + +`````bru +meta { + name: Create Application + type: http +} + +post /applications + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "universityId": 1, + "choice": "first" + } +} + +docs { + ````json + { + "id": 123, + "status": "pending", + "submittedAt": "2025-11-12T05:30:00Z" + } + ```` +} +````` + +### GET - 상세 조회 (Path Parameter) + +`````bru +meta { + name: Get Application Detail + type: http +} + +get /applications/:id + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "id": 123, + "userId": 456, + "status": "approved", + "reviewer": { + "id": 789, + "name": "심사자" + } + } + ```` +} +````` + +## MSW 생성 제어 + +MSW 핸들러는 모든 API에 대해 생성되며, **프론트엔드에서 플래그로 활성/비활성을 제어**합니다. + +### 프론트엔드에서 MSW 제어 + +생성된 `handlers.ts` 파일에서 환경 변수나 설정으로 제어할 수 있습니다: + +**예시 1: 환경 변수로 제어** + +```typescript +// src/mocks/handlers.ts +import { authHandlers } from "./Auth"; +import { usersHandlers } from "./Users"; + +const ENABLE_MSW = process.env.NEXT_PUBLIC_ENABLE_MSW === "true"; + +export const handlers = ENABLE_MSW ? [...authHandlers, ...usersHandlers] : []; +``` + +**예시 2: 특정 도메인만 활성화** + +```typescript +export const handlers = [ + ...authHandlers, // Auth 도메인만 활성화 + // ...usersHandlers, // Users 도메인 비활성화 +]; +``` + +**예시 3: 조건부 필터링** + +```typescript +const enabledDomains = ["Auth", "Users"]; // 활성화할 도메인 목록 + +export const handlers = [ + ...(enabledDomains.includes("Auth") ? authHandlers : []), + ...(enabledDomains.includes("Users") ? usersHandlers : []), +]; +``` + +## 체크리스트 + +새 API 엔드포인트를 만들 때: + +- [ ] `meta` 블록 작성 (name 필수) +- [ ] HTTP 메서드와 경로 명확히 표기 +- [ ] 인증 필요시 `headers` 블록에 Authorization +- [ ] POST/PUT이면 `body:json` 블록 작성 +- [ ] **`docs` 블록 반드시 작성** (가장 중요!) +- [ ] JSON이 유효한가? (온라인 validator로 확인) +- [ ] 모든 필드가 포함되었나? +- [ ] 배열에 최소 1개 요소가 있나? +- [ ] 날짜는 ISO 8601 형식인가? + +## 빠른 템플릿 + +### GET 템플릿 + +````bru +meta { + name: [API 이름] + type: http +} + +get /[경로] + +headers { + Authorization: Bearer {{token}} +} + +docs { + ```json + { + "id": 1, + "field": "value" + } +```` + +} + +```` + +### POST 템플릿 + +```bru +meta { + name: [API 이름] + type: http +} + +post /[경로] + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "field": "value" + } +} + +docs { + ```json + { + "id": 1, + "status": "success" + } +```` + +} + +``` + +## 문제 해결 + +1. **파싱 에러**: docs 블록의 JSON을 복사해서 [JSONLint](https://jsonlint.com/)로 검증 +2. **타입이 이상함**: 값의 타입 확인 (숫자는 따옴표 없이, 문자열은 따옴표) +3. **필드가 안보임**: docs 블록에 해당 필드 추가했는지 확인 + +--- + +**핵심은 `docs` 블록을 정확하게 작성하는 것!** +``` diff --git a/packages/bruno-api-typescript/docs/bruno-tutorial.md b/packages/bruno-api-typescript/docs/bruno-tutorial.md new file mode 100644 index 00000000..18b0d594 --- /dev/null +++ b/packages/bruno-api-typescript/docs/bruno-tutorial.md @@ -0,0 +1,607 @@ +# Bruno 파일 작성 튜토리얼 (따라하기) + +> **단계별로 따라하면서 Bruno 파일 작성을 마스터하세요** + +## 시작하기 전에 + +### 필요한 도구 + +1. **텍스트 에디터** (VS Code, Cursor 등) +2. **Bruno 앱** (선택사항) - [다운로드](https://www.usebruno.com/downloads) + +### 폴더 구조 준비 + +```bash +mkdir -p bruno/users +mkdir -p bruno/products +``` + +--- + +## 튜토리얼 1: 첫 GET 요청 만들기 + +### 목표 + +사용자 프로필을 조회하는 API 작성 + +### 단계 1: 파일 생성 + +```bash +touch bruno/users/profile.bru +``` + +> ⚠️ **주의**: 파일명에 HTTP 메서드(`get-`, `post-` 등)를 포함하지 마세요. 메서드는 파일 내부에서 정의됩니다. + +### 단계 2: meta 블록 작성 + +파일을 열고 다음을 입력하세요: + +```bru +meta { + name: Get User Profile + type: http +} +``` + +**설명**: + +- `name`: API 이름 (자유롭게 작성) +- `type`: 항상 `http` + +### 단계 3: HTTP 메서드와 경로 추가 + +```bru +meta { + name: Get User Profile + type: http +} + +get /users/profile +``` + +**설명**: + +- `get`: HTTP 메서드 (소문자) +- `/users/profile`: API 경로 + +### 단계 4: 헤더 추가 + +```bru +meta { + name: Get User Profile + type: http +} + +get /users/profile + +headers { + Authorization: Bearer {{token}} +} +``` + +**설명**: + +- 인증이 필요한 API는 `Authorization` 헤더 추가 +- `{{token}}`: Bruno 변수 (나중에 설정) + +### 단계 5: docs 블록 추가 (가장 중요!) + +`````bru +meta { + name: Get User Profile + type: http +} + +get /users/profile + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "id": 1, + "username": "johndoe", + "email": "john@example.com", + "firstName": "John", + "lastName": "Doe", + "createdAt": "2025-01-01T00:00:00Z" + } + ```` +} +````` + +**설명**: + +- `docs` 블록에 **실제 API 응답 JSON** 작성 +- 이 JSON으로 타입이 자동 생성됩니다! + +### 완성! + +첫 Bruno 파일 완성입니다! + +**참고**: 이 프로젝트는 GitHub Actions에서 자동으로 실행됩니다. 로컬에서 테스트하려면 저장소를 클론하고 빌드한 후 사용하세요. + +**생성되는 코드**: +```typescript +// src/apis/users/api.ts +export const usersApi = { + getProfile: async (params: { params?: Record }): Promise => { + const res = await axiosInstance.get(`/users/profile`, { params: params?.params }); + return res.data; + } +}; +``` + +--- + +## 튜토리얼 2: POST 요청 만들기 + +### 목표 + +상품을 생성하는 API 작성 + +### 단계 1: 파일 생성 + +```bash +touch bruno/products/create-product.bru +``` + +### 단계 2: 기본 구조 작성 + +```bru +meta { + name: Create Product + type: http +} + +post /products + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} +``` + +### 단계 3: 요청 body 추가 + +```bru +meta { + name: Create Product + type: http +} + +post /products + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "name": "Laptop", + "price": 1200.50, + "category": "Electronics", + "inStock": true + } +} +``` + +**설명**: + +- `body:json`: POST/PUT 요청 시 필요 +- 중괄호 안에 JSON 작성 + +### 단계 4: 응답 docs 추가 + +`````bru +meta { + name: Create Product + type: http +} + +post /products + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "name": "Laptop", + "price": 1200.50, + "category": "Electronics", + "inStock": true + } +} + +docs { + ````json + { + "id": 101, + "name": "Laptop", + "price": 1200.50, + "category": "Electronics", + "inStock": true, + "createdAt": "2025-12-23T00:00:00Z", + "message": "Product created successfully" + } + ```` +} +````` + +### 완성! + +POST 요청이 완성되었습니다. + +--- + +## 튜토리얼 3: Path Parameter 사용하기 + +### 목표 + +특정 상품을 조회하는 API 작성 (`/products/:id`) + +### 단계 1: 파일 생성 + +```bash +touch bruno/products/product.bru +``` + +> ⚠️ **주의**: 파일명에 HTTP 메서드를 포함하지 마세요. + +### 단계 2: Path Parameter 포함 경로 작성 + +`````bru +meta { + name: Get Product by ID + type: http +} + +get /products/:id + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "id": 101, + "name": "Laptop", + "price": 1200.50, + "category": "Electronics", + "inStock": true, + "description": "High-performance laptop for professionals", + "createdAt": "2025-12-23T00:00:00Z" + } + ```` +} +````` + +**설명**: + +- `:id`: Path Parameter (동적 값) +- docs에는 실제 응답 예시 작성 + +### Bruno 앱에서 테스트하기 + +Bruno 앱에서: + +1. 파일 열기 +2. `:id` 부분에 `101` 입력 +3. Send 버튼 클릭 + +--- + +## 튜토리얼 4: Query Parameter 사용하기 + +### 목표 + +필터링이 가능한 상품 목록 조회 (`/products?category=Electronics&inStock=true`) + +`````bru +meta { + name: Get Products List + type: http +} + +get /products + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "products": [ + { + "id": 101, + "name": "Laptop", + "price": 1200.50, + "category": "Electronics", + "inStock": true + }, + { + "id": 102, + "name": "Mouse", + "price": 25.00, + "category": "Electronics", + "inStock": true + } + ], + "total": 2, + "page": 1, + "pageSize": 10 + } + ```` +} +````` + +**설명**: + +- Query Parameter는 경로에 적지 않아도 됨 +- docs에 배열 응답 예시 작성 (최소 1개 요소 필요!) + +--- + +## 튜토리얼 5: 한글 폴더명 및 파일명 사용하기 + +### 한글 폴더명 지원 + +**권장 형식: `숫자) 한글명 [영문키]`** + +```bash +mkdir "bruno/7) 어드민 [Admin]" +touch "bruno/7) 어드민 [Admin]/목록 조회 [list].bru" +``` + +**규칙**: + +- `숫자) 한글명 [영문키]` 형식 (권장) +- `한글명 [영문키]` 형식 (기존 호환) +- 대괄호 `[]` 안의 영문키만 사용됨 + +**예시**: + +``` +bruno/ +├── 7) 어드민 [Admin]/ → Admin으로 인식 +├── 8) 사용자 [Users]/ → Users로 인식 +├── 지원서 [applications]/ → applications로 인식 (기존 방식) +└── 상품 [products]/ → products로 인식 (기존 방식) +``` + +### 한글 파일명 지원 + +**권장 형식: `한글명 [영문키]`** + +> ⚠️ **중요**: 파일명에 **HTTP 메서드를 포함하지 마세요**. 메서드는 `.bru` 파일 내부에서 자동으로 인식됩니다. + +```bash +touch "bruno/7) 어드민 [Admin]/목록 조회 [list].bru" +touch "bruno/7) 어드민 [Admin]/생성 [create].bru" +``` + +**규칙**: + +- `한글명 [영문키]` 형식 +- 대괄호 `[]` 안의 영문키만 사용됨 +- **HTTP 메서드 prefix는 포함하지 않음** (예: `get-`, `post-` 등) +- 예: `목록 조회 [list].bru` → `list` → `getList` (GET 메서드인 경우) +- 예: `생성 [create].bru` → `create` → `postCreate` (POST 메서드인 경우) + +--- + +## 실전 연습 + +### 연습 1: 상품 삭제 API 만들기 + +**조건**: + +- DELETE 메서드 +- 경로: `/products/:id` +- 응답: `{ "success": true, "message": "Product deleted" }` + +
+정답 보기 + +`````bru +meta { + name: Delete Product + type: http +} + +delete /products/:id + +headers { + Authorization: Bearer {{token}} +} + +docs { + ````json + { + "success": true, + "message": "Product deleted", + "deletedId": 101 + } + ```` +} +````` + +
+ +### 연습 2: 상품 업데이트 API 만들기 + +**조건**: + +- PUT 메서드 +- 경로: `/products/:id` +- 요청 body: 가격과 재고 상태 업데이트 +- 응답: 업데이트된 상품 정보 + +
+정답 보기 + +`````bru +meta { + name: Update Product + type: http +} + +put /products/:id + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "price": 999.99, + "inStock": false + } +} + +docs { + ````json + { + "id": 101, + "name": "Laptop", + "price": 999.99, + "category": "Electronics", + "inStock": false, + "updatedAt": "2025-12-23T01:00:00Z" + } + ```` +} +````` + +
+ +--- + +## 일반적인 실수와 해결방법 + +### 실수 1: JSON 형식 오류 + +**❌ 잘못된 예시:** + +`````bru +docs { + ````json + { + id: 1, // 키에 따옴표 없음 + "name": '홍길동' // 작은따옴표 사용 + } + ```` +} +````` + +**✅ 올바른 예시:** + +`````bru +docs { + ````json + { + "id": 1, + "name": "홍길동" + } + ```` +} +````` + +**해결**: [JSONLint](https://jsonlint.com/)에서 JSON 검증 + +### 실수 2: 빈 배열 + +**❌ 잘못된 예시:** + +`````bru +docs { + ````json + { + "products": [] // 타입 추론 불가 + } + ```` +} +````` + +**✅ 올바른 예시:** + +`````bru +docs { + ````json + { + "products": [ + { + "id": 1, + "name": "예시" + } + ] + } + ```` +} +````` + +### 실수 3: docs 블록 누락 + +**❌ 잘못된 예시:** + +```bru +meta { + name: Get User + type: http +} + +get /users/profile + +headers { + Authorization: Bearer {{token}} +} + +# docs 블록이 없음! +``` + +**해결**: docs 블록은 필수입니다! + +--- + +## 체크리스트 + +새 Bruno 파일을 작성한 후: + +- [ ] `meta` 블록 작성 (name 필수) +- [ ] HTTP 메서드와 경로 명확히 표기 +- [ ] 인증 필요시 `headers` 블록에 Authorization +- [ ] POST/PUT이면 `body:json` 블록 작성 +- [ ] **`docs` 블록 반드시 작성** +- [ ] JSON이 유효한가? ([JSONLint](https://jsonlint.com/)로 확인) +- [ ] 모든 필드가 포함되었나? +- [ ] 배열에 최소 1개 요소가 있나? +- [ ] 날짜는 ISO 8601 형식인가? (`2025-01-01T00:00:00Z`) + +--- + +## 다음 단계 + +축하합니다! Bruno 파일 작성을 마스터했습니다. + +**다음으로 할 일**: + +1. 실제 API 엔드포인트로 Bruno 파일 작성 +2. OpenAPI 생성: `npm run api:generate` +3. API 클라이언트 생성: `npm run api:hooks` + +**더 알아보기**: + +- [Bruno 파일 작성 가이드](./bruno-guide.md) - 레퍼런스 +-- [빠른 시작](./quickstart.md) - 명령어 정리 + +--- + +**Happy Coding! 🚀** diff --git a/packages/bruno-api-typescript/docs/github-apps-simple.md b/packages/bruno-api-typescript/docs/github-apps-simple.md new file mode 100644 index 00000000..f77bfc92 --- /dev/null +++ b/packages/bruno-api-typescript/docs/github-apps-simple.md @@ -0,0 +1,279 @@ +# GitHub Apps 연결 (5분 가이드) + +> Bruno 저장소와 프론트엔드 저장소를 자동으로 연결하여 변경사항을 자동 PR로 생성 + +## 왜 필요한가? + +Bruno 저장소에서 `.bru` 파일이 변경되면, 프론트엔드 저장소에 자동으로: + +- API 클라이언트 생성 +- TypeScript 타입 생성 +- PR 자동 생성 + +**결과**: 백엔드 개발자가 Bruno 파일만 수정하면, 프론트엔드 개발자는 PR만 확인하면 끝! + +--- + +## 5분 설정 + +### 1단계: GitHub App 생성 (2분) + +#### 1-1. GitHub Settings 이동 + +1. GitHub 우측 상단 프로필 → **Settings** +2. 왼쪽 메뉴 하단 → **Developer settings** +3. **GitHub Apps** → **New GitHub App** + +#### 1-2. 앱 정보 입력 + +**필수 입력 사항**: + +- GitHub App name: `bruno-sync-app` (조직명 추가 가능) +- Homepage URL: `https://github.com/your-org/bruno-api` +- Webhook: **비활성화** (체크 해제) + +**권한 설정 (Repository permissions)**: + +- **Contents**: Read & Write +- **Pull requests**: Read & Write +- **Workflows**: Read & Write + +**Where can this GitHub App be installed?**: + +- **Only on this account** 선택 (조직 계정이면 조직 선택) + +#### 1-3. 생성 및 Private Key 다운로드 + +1. **Create GitHub App** 클릭 +2. 생성된 앱 페이지에서 스크롤 다운 +3. **Generate a private key** 클릭 +4. `bruno-sync-app.{date}.private-key.pem` 파일 다운로드 + +**App ID 복사**: + +- 페이지 상단에 표시된 **App ID** 복사 (예: `123456`) + +### 2단계: App 설치 (1분) + +#### 2-1. 앱 설치 + +1. GitHub App 설정 페이지에서 **Install App** (왼쪽 메뉴) +2. 조직 또는 개인 계정 선택 +3. **All repositories** 또는 **Only select repositories** 선택 + - Bruno 저장소와 프론트엔드 저장소 선택 +4. **Install** 클릭 + +#### 2-2. Installation ID 확인 + +설치 후 URL을 확인하세요: + +``` +https://github.com/settings/installations/{installation_id} +``` + +`{installation_id}` 숫자를 복사하세요 (예: `789012`) + +### 3단계: Secrets 설정 (1분) + +#### Bruno 저장소 Secrets + +Bruno 저장소 → **Settings** → **Secrets and variables** → **Actions** → **New repository secret** + +다음 3개 Secret 추가: + +1. **APP_ID**: `123456` (1단계에서 복사한 App ID) +2. **APP_PRIVATE_KEY**: `bruno-sync-app.pem` 파일 전체 내용 복사 붙여넣기 +3. **INSTALLATION_ID**: `789012` (2단계에서 확인한 Installation ID) + +#### 프론트엔드 저장소 Secrets + +프론트엔드 저장소 → **Settings** → **Secrets and variables** → **Actions** → **New repository secret** + +동일한 3개 Secret 추가 (값 동일) + +### 4단계: Workflow 파일 추가 (1분) + +#### Bruno 저장소 Workflow + +파일: `.github/workflows/sync-to-frontend.yml` + +```yaml +name: Sync to Frontend + +on: + push: + branches: + - main + paths: + - "**/*.bru" + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + repositories: "frontend-repo" # 프론트엔드 저장소 이름 + + - name: Trigger Frontend Workflow + run: | + curl -X POST \ + -H "Authorization: Bearer ${{ steps.app-token.outputs.token }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository_owner }}/frontend-repo/dispatches \ + -d '{"event_type":"bruno_updated","client_payload":{"sha":"${{ github.sha }}"}}' +``` + +**수정 필요**: + +- `frontend-repo`: 실제 프론트엔드 저장소 이름으로 변경 + +#### 프론트엔드 저장소 Workflow + +파일: `.github/workflows/sync-from-bruno.yml` + +```yaml +name: Sync from Bruno + +on: + repository_dispatch: + types: [bruno_updated] + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Generate App Token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + + - name: Clone Bruno Repo + run: | + git clone https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${{ github.repository_owner }}/bruno-api.git /tmp/bruno + + - name: Clone bruno-api-typescript + run: | + git clone https://github.com/solid-connection/bruno-api-typescript.git /tmp/bruno-api-typescript + + - uses: actions/setup-node@v4 + with: + node-version: "18" + + - name: Build bruno-api-typescript + working-directory: /tmp/bruno-api-typescript + run: | + npm install + npm run build + + - name: Generate API Clients + run: | + node /tmp/bruno-api-typescript/dist/cli/index.js generate-hooks -i /tmp/bruno -o ./src/apis + + - name: Create PR + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ steps.app-token.outputs.token }} + commit-message: "chore: sync API from Bruno" + branch: api-sync-${{ github.run_number }} + title: "🔄 API Sync from Bruno" + body: | + ## Bruno API 자동 동기화 + + Bruno 저장소가 업데이트되어 자동으로 API 클라이언트를 생성했습니다. + + **변경사항**: + - API 클라이언트 업데이트 + - TypeScript 타입 업데이트 +``` + +**수정 필요**: + +- `bruno-api`: 실제 Bruno 저장소 이름으로 변경 +- `bruno-api-typescript`: 실제 bruno-api-typescript 저장소 이름으로 변경 (기본값: `solid-connection/bruno-api-typescript`) + +--- + +## 테스트 + +### Bruno 파일 수정 후 푸시 + +```bash +# Bruno 저장소에서 +vim users/get-profile.bru +git add . +git commit -m "feat: add email field" +git push origin main +``` + +### 확인 + +1. Bruno 저장소 Actions 탭 확인 +2. 프론트엔드 저장소 Actions 탭 확인 +3. 프론트엔드 저장소 Pull Requests 확인 + +**예상 결과**: 약 1-2분 후 프론트엔드 저장소에 PR 자동 생성! + +--- + +## 트러블슈팅 + +### 1. "Resource not accessible by integration" 에러 + +**원인**: App 권한 부족 + +**해결**: + +1. GitHub App 설정 → **Permissions** 확인 +2. Contents, Pull requests, Workflows가 **Read & Write**인지 확인 +3. 권한 변경 후 → **Install App** → 재설치 + +### 2. Private Key 오류 + +**원인**: Secret에 키가 잘못 입력됨 + +**해결**: + +1. `.pem` 파일을 텍스트 에디터로 열기 +2. `-----BEGIN RSA PRIVATE KEY-----`부터 `-----END RSA PRIVATE KEY-----`까지 전체 복사 +3. Secret 다시 생성 + +### 3. Workflow가 트리거 안됨 + +**원인**: `.bru` 파일이 변경되지 않음 + +**해결**: + +- Bruno 저장소에서 `.bru` 파일을 수정하고 푸시 +- Workflow 파일의 `paths` 필터 확인 + +### 4. "npm error 404 Not Found - bruno-api-typescript" 에러 + +**원인**: npm 패키지가 아니므로 `npx`로 실행 불가 + +**해결**: + +- Workflow에서 저장소를 클론하고 빌드한 후 사용 +- 위의 Workflow 예시처럼 `git clone` → `npm install` → `npm run build` → `node dist/cli/index.js` 순서로 실행 + +--- + +## 더 자세한 가이드 + +심화 내용은 [상세 GitHub Apps 가이드](./archived/github-apps.md)를 참조하세요. + +--- + +**설정 완료! 🎉** diff --git a/packages/bruno-api-typescript/docs/migration-guide.md b/packages/bruno-api-typescript/docs/migration-guide.md new file mode 100644 index 00000000..56f6fdf0 --- /dev/null +++ b/packages/bruno-api-typescript/docs/migration-guide.md @@ -0,0 +1,128 @@ +# API 클라이언트 변경사항 처리 가이드 + +## 개요 + +이 프로젝트는 Bruno 파일에서 타입 안전한 API 클라이언트를 자동 생성합니다. 변경사항은 다음과 같이 처리됩니다: + +1. **API 팩토리 (api.ts)**: 항상 덮어쓰기 (최신 API 시그니처 유지) +2. **API 정의 (apiDefinitions.ts)**: 항상 덮어쓰기 (타입 메타데이터 최신화) + +## 파일 구조 + +``` +src/apis/ +├── Auth/ +│ ├── api.ts # API 팩토리 (항상 덮어쓰기) +│ ├── apiDefinitions.ts # 타입 정의 (항상 덮어쓰기) +│ └── index.ts +``` + +## 동작 방식 + +### 1. 새 API 추가 시 + +새 API가 추가되면 팩토리와 정의 파일이 업데이트됩니다. + +``` +Auth/ +├── api.ts # authApi.postSignOut 추가됨 +├── apiDefinitions.ts # postSignOut 타입 정의 추가됨 +└── index.ts +``` + +### 2. 기존 API 변경 시 + +API 시그니처가 변경되면 자동으로 반영됩니다. + +``` +Auth/ +├── api.ts # authApi.postSignOut 업데이트됨 +├── apiDefinitions.ts # postSignOut 타입 정의 업데이트됨 +└── index.ts +``` + +## 사용 방법 + +### API 호출 + +생성된 API 클라이언트는 다음과 같이 사용합니다: + +```typescript +import { authApi } from '@/apis/Auth'; + +// GET 요청 +const profile = await authApi.getProfile({ params: { includeDetails: true } }); + +// POST 요청 +const result = await authApi.postSignOut({ data: {} }); +``` + + +## 타입 정의 활용 + +### API 메타데이터 확인 + +`apiDefinitions.ts`는 각 API의 타입 메타데이터를 제공합니다: + +```typescript +import { authApiDefinitions } from '@/apis/Auth'; + +// API 메타데이터 확인 +const signOutDef = authApiDefinitions.postSignOut; +console.log(signOutDef.method); // 'POST' +console.log(signOutDef.path); // '/auth/sign-out' + +// 타입 추론 +type SignOutRequest = typeof signOutDef.body; +type SignOutResponse = typeof signOutDef.response; +``` + +### 타입 안전성 + +모든 API 호출은 완전한 타입 안전성을 제공합니다: + +```typescript +// ✅ 올바른 사용 +await authApi.postSignOut({ + data: { /* PostSignOutRequest 타입 */ } +}); + +// ❌ 컴파일 에러 +await authApi.postSignOut({ + data: { invalidField: true } // 타입 에러 +}); +``` + +## 주의사항 + +### 생성 파일 커스터마이징 금지 + +`api.ts`와 `apiDefinitions.ts` 파일은 항상 덮어쓰기되므로, 이 파일들을 직접 수정하지 마세요. + +### 커스텀 로직 분리 + +비즈니스 로직이나 커스텀 훅은 별도 파일로 관리하세요: + +``` +src/ +├── apis/ +│ └── Auth/ +│ ├── api.ts # 자동 생성 (수정 금지) +│ └── apiDefinitions.ts # 자동 생성 (수정 금지) +└── hooks/ + └── useAuth.ts # 커스텀 훅 (자유롭게 수정) +``` + +## 자주 묻는 질문 + +### Q: API 팩토리 파일을 수정해도 되나요? + +A: 아니요. `api.ts`와 `apiDefinitions.ts`는 자동 생성 파일이므로 수정하지 마세요. 다음 생성 시 덮어쓰기됩니다. + +### Q: 커스텀 로직은 어디에 추가하나요? + +A: 별도의 훅 파일(`src/hooks/`)을 만들어 커스텀 로직을 관리하세요. 자동 생성된 API 클라이언트를 import하여 사용합니다. + +### Q: API 클라이언트를 직접 사용해도 되나요? + +A: 네, API 클라이언트와 API 정의는 독립적으로 사용할 수 있습니다. 필요하다면 별도의 레이어에서 커스텀 훅을 만들어 사용하세요. diff --git a/packages/bruno-api-typescript/docs/prd-react-query-removal.md b/packages/bruno-api-typescript/docs/prd-react-query-removal.md new file mode 100644 index 00000000..23b10670 --- /dev/null +++ b/packages/bruno-api-typescript/docs/prd-react-query-removal.md @@ -0,0 +1,120 @@ +# PRD: React Query 제거 및 타입/쿼리 동기화 강화 + +## 1. 배경 / 문제 정의 +현재 이 레포는 Bruno `.bru` 정의를 기반으로 OpenAPI와 React Query hooks를 생성하도록 설계되어 있습니다. 목표는 **React Query 의존을 제거**하고, **타입을 확실하게 보장**하며, **쿼리(요청) 정보가 완벽히 동기화된 산출물**을 제공하는 것입니다. 즉, React Query 훅 생성이 아닌 **정확한 타입/요청 정의 생성과 변경 동기화**가 핵심 목표입니다. + +## 2. 목표 (Goals) +1. **React Query 지원 제거**: 훅 생성 및 관련 문서/옵션/출력물을 제거 또는 대체. +2. **타입 정확도 강화**: Bruno docs의 JSON 예제 기반 타입 생성의 정확성을 강화하고, 불확실한 타입의 범위를 최소화. +3. **쿼리 정보 완전 동기화**: 요청 정보(메서드, URL, path/query params, request/response schema)가 항상 정확히 동기화된 산출물로 제공. + +## 3. 비목표 (Non-Goals) +- 외부 클라이언트 프레임워크(React Query 외) 추가 지원은 본 범위에 포함하지 않음. +- 런타임 SDK/HTTP 클라이언트 교체는 별도 범위로 분리. + +## 4. 사용자 스토리 +1. 백엔드 개발자는 Bruno 파일만 수정하면 **타입과 요청 정의가 자동으로 최신화**되길 원한다. +2. 프론트엔드 개발자는 **React Query 훅 없이도** 타입과 요청 정보가 완벽히 동기화된 산출물을 받길 원한다. +3. 변경 발생 시 **동기화 상태와 변경 내역을 명확히 파악**할 수 있길 원한다. + +## 5. 주요 요구사항 + +### 5.1 기능 요구사항 +1. **React Query 훅 생성 제거** + - `reactQueryGenerator.ts`, `queryKeyGenerator.ts`, hook 관련 CLI 옵션/문서에서 제거 또는 대체. + - `docs/migration-guide.md`의 React Query 훅 기반 워크플로우 제거 또는 재작성. + +2. **정확한 타입 산출** + - `typeGenerator.ts`의 타입 생성 로직 검증 강화. + - Bruno docs JSON 예제를 기반으로 **정확한 타입 선언 생성** (리터럴 → 일반 타입, 배열/객체/유니온에 대한 안정적 추론). + +3. **쿼리 정보 동기화 산출물 제공** + - 각 API 요청에 대해 **요청 메타데이터 + 타입 정보**를 함께 출력. + - 예: `apiDefinitions.ts` (또는 유사)로 모든 API 스펙을 타입 안전하게 노출. + - 변경 감지(캐시/디프) 결과가 이 산출물에도 적용되어 **변경 시 자동 동기화**. + +### 5.2 비기능 요구사항 +1. **완전 자동화**: 기존 CLI (`generate`, `generate-hooks`) 흐름에서 React Query 훅 제거 후에도 자동 생성 파이프라인이 유지되어야 함. +2. **정확성 우선**: 추론 실패 시 명확한 에러/경고 제공. +3. **호환성**: 기존 생성 파이프라인의 캐시/변경 감지 로직과 함께 동작. + +## 6. 산출물 정의 + +### 6.1 기존 산출물 제거 +- `src/apis/**` 내 React Query hooks +- `queryKeys.ts` + +### 6.2 신규 산출물 +1. **API 정의/타입 파일** (예: `src/apis/apiDefinitions.ts`) + - 각 API의 메서드/경로/파라미터/응답 타입을 구조적으로 표현 + - 예시: + ```ts + export const ApiDefinitions = { + users: { + getUser: { + method: "GET", + path: "/users/:userId", + params: { userId: "number" }, + response: {} as GetUserResponse, + }, + }, + } as const; + ``` + +2. **타입 정의 파일** + - 기존 `apiClientGenerator.ts` / `apiFactoryGenerator.ts`가 제공하는 타입 산출은 유지하되, React Query 의존이 없는 형태로 재구성. + +## 7. 변경 범위 (Scope) + +### 7.1 제거 대상 +- `src/generator/reactQueryGenerator.ts` +- `src/generator/queryKeyGenerator.ts` +- React Query 관련 문서 (README, migration-guide, querykey spec) +- CLI 명령 `generate-hooks` 혹은 해당 명령의 React Query 전용 옵션 + +### 7.2 수정 대상 +- `src/generator/index.ts` +- `src/cli/index.ts` +- 문서/가이드: README, docs/* + +### 7.3 유지 대상 +- OpenAPI 생성 로직 (`openapiConverter`, `schemaBuilder`) +- 타입 생성 로직 (`typeGenerator`, `apiClientGenerator`, `apiFactoryGenerator`) +- 캐시/변경 감지 로직 (`brunoHashCache`, `changeDetector`) + +## 8. 성공 기준 (Success Metrics) +1. React Query 관련 코드/문서/출력이 전부 제거되거나 대체됨. +2. 모든 API 정의가 타입 안전하게 산출됨. +3. 변경 감지/동기화 파이프라인이 정상 작동하며, 타입/정의 산출물이 최신 상태로 유지됨. + +## 9. 리스크 및 대응 +| 리스크 | 영향 | 대응 | +|-------|------|------| +| 기존 사용자/프론트엔드 워크플로우 영향 | 높음 | 마이그레이션 문서 제공, 레거시 출력 옵션 고려 | +| 타입 추론 정확도 한계 | 중간 | docs JSON 예제 규칙 강화, 실패 시 명확한 에러 제공 | +| 내부 CLI 변경에 따른 기존 스크립트 오류 | 중간 | 새로운 CLI 명령/옵션 명세 제공 | + +## 10. 실행 계획 (Phased Plan) + +### Phase 1: 구조 정리 및 React Query 제거 +- React Query generator 제거 +- CLI 옵션/명령 정리 +- 관련 문서 제거/업데이트 + +### Phase 2: 타입/정의 산출물 강화 +- 타입 생성 로직 보강 +- API 정의 메타데이터 파일 생성 +- 출력 구조 명세화 + +### Phase 3: 동기화 및 변경 감지 연계 +- 캐시/디프/변경 감지 결과와 산출물 동기화 +- 변경 리포트 문서 업데이트 + +### Phase 4: 문서 및 마이그레이션 +- README 및 docs 전면 정비 +- 기존 사용자 대상 마이그레이션 가이드 제공 + +## 11. 오픈 이슈 +- React Query 제거 후 CLI 명령 네이밍 (`generate-hooks` 유지 여부) +- 기존 훅 기반 프론트엔드와의 호환 전략 +- 타입 추론 실패 기준 및 에러 처리 정책 diff --git a/packages/bruno-api-typescript/docs/usage-guide.md b/packages/bruno-api-typescript/docs/usage-guide.md new file mode 100644 index 00000000..1252713e --- /dev/null +++ b/packages/bruno-api-typescript/docs/usage-guide.md @@ -0,0 +1,120 @@ +# 사용 방법 가이드 + +> 이 문서는 `bruno-api-typescript`를 실제 프로젝트에서 사용하는 방법을 설명합니다. + +## 목표 + +- Bruno `.bru` 정의로부터 **OpenAPI 스펙**과 **타입 안전한 API 클라이언트**를 생성합니다. +- 빌드/개발 과정에서 **항상 최신 스키마**를 바라보도록 실행 흐름을 구성합니다. + +## 사전 준비 + +1. **Node.js 18+** +2. Bruno `.bru` 파일이 있는 디렉토리 +3. `npm install` 및 `npm run build` 완료 + +## 핵심 명령어 + +### 1) OpenAPI 생성 + +```bash +node dist/cli/index.js generate -i ./bruno -o ./openapi.json +``` + +### 2) API 클라이언트/정의 생성 + +```bash +node dist/cli/index.js generate-hooks -i ./bruno -o ./src/apis +``` + +**옵션 예시**: + +```bash +node dist/cli/index.js generate-hooks \ + -i ./bruno \ + -o ./src/apis \ + --axios-path "@/utils/axiosInstance" \ + --msw-output ./src/mocks +``` + +## 권장 파일 구조 + +``` +bruno/ +├── users/ +│ └── profile.bru +└── applications/ + └── create-application.bru + +src/ +└── apis/ + ├── users/ + │ ├── api.ts + │ ├── apiDefinitions.ts + │ └── index.ts + └── applications/ + ├── api.ts + ├── apiDefinitions.ts + └── index.ts +``` + +## 생성 결과 사용법 + +### API 호출 + +```ts +import { usersApi } from '@/apis/users'; + +const profile = await usersApi.getGetProfile({ + params: { includeDetails: true }, +}); +``` + +### API 정의 메타데이터 + +```ts +import { usersApiDefinitions } from '@/apis/users'; + +const def = usersApiDefinitions.getGetProfile; +console.log(def.method); // 'GET' +console.log(def.path); // '/users/profile' + +type ProfileResponse = typeof def.response; +``` + +## 빌드/개발 파이프라인에 통합하기 + +### ✅ 목표: 항상 최신 스키마를 바라보도록 자동 생성 + +빌드 또는 개발 실행 전에 자동으로 OpenAPI/클라이언트를 생성하도록 **스크립트를 연결**합니다. + +#### 예시: `package.json` 스크립트 + +```json +{ + "scripts": { + "api:generate": "node dist/cli/index.js generate -i ./bruno -o ./openapi.json", + "api:clients": "node dist/cli/index.js generate-hooks -i ./bruno -o ./src/apis", + "build": "npm run api:generate && npm run api:clients && tsc", + "dev": "npm run api:generate && npm run api:clients && tsc --watch" + } +} +``` + +> 이렇게 구성하면 **빌드와 개발 실행 시 항상 최신 스키마/클라이언트를 보장**합니다. + +## 자주 묻는 질문 + +### Q. 생성 파일을 수정해도 되나요? + +A. 안 됩니다. `api.ts`, `apiDefinitions.ts`는 자동 생성 파일이며, 다음 실행 시 덮어쓰기됩니다. + +### Q. 커스텀 로직은 어디에 두나요? + +`src/hooks/` 또는 별도 레이어에서 API 클라이언트를 불러와 사용하는 것을 권장합니다. + +## 관련 문서 + +- [Bruno 파일 작성 가이드](./bruno-guide.md) +- [Bruno 파일 작성 튜토리얼](./bruno-tutorial.md) +- [변경사항 처리 가이드](./migration-guide.md) diff --git a/packages/bruno-api-typescript/package-lock.json b/packages/bruno-api-typescript/package-lock.json new file mode 100644 index 00000000..21f5f504 --- /dev/null +++ b/packages/bruno-api-typescript/package-lock.json @@ -0,0 +1,552 @@ +{ + "name": "bruno-api-typescript", + "version": "0.3.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bruno-api-typescript", + "version": "0.3.0", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "glob": "^10.3.10", + "yaml": "^2.3.4" + }, + "bin": { + "bruno-api": "dist/cli/index.js" + }, + "devDependencies": { + "@types/node": "^20.10.6", + "typescript": "^5.3.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "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==", + "license": "ISC", + "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/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/node": { + "version": "20.19.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", + "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "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/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "license": "ISC", + "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/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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "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==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "BlueOak-1.0.0", + "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/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==", + "license": "MIT", + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "license": "MIT", + "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==", + "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/string-width-cjs/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/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==", + "license": "MIT" + }, + "node_modules/string-width-cjs/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/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "license": "MIT", + "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==", + "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/wrap-ansi-cjs/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/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==", + "license": "MIT", + "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/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/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==", + "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/wrap-ansi-cjs/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/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + } + } +} diff --git a/packages/bruno-api-typescript/package.json b/packages/bruno-api-typescript/package.json new file mode 100644 index 00000000..f2d390c4 --- /dev/null +++ b/packages/bruno-api-typescript/package.json @@ -0,0 +1,36 @@ +{ + "name": "bruno-api-typescript", + "version": "0.3.0", + "description": "Automate API sync between Bruno and Frontend via GitHub Apps", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "bruno-api": "./dist/cli/index.js" + }, + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "test": "node --test" + }, + "private": true, + "keywords": [ + "bruno", + "openapi", + "github-apps", + "automation" + ], + "author": "MANWOOK", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "glob": "^10.3.10", + "yaml": "^2.3.4" + }, + "devDependencies": { + "@types/node": "^20.10.6", + "typescript": "^5.3.3" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/packages/bruno-api-typescript/scripts/setup-cross-repo.sh b/packages/bruno-api-typescript/scripts/setup-cross-repo.sh new file mode 100755 index 00000000..6df6f12b --- /dev/null +++ b/packages/bruno-api-typescript/scripts/setup-cross-repo.sh @@ -0,0 +1,231 @@ +#!/bin/bash + +# Bruno-Frontend Cross-Repo 자동 연동 설정 스크립트 + +set -e + +echo "🚀 Bruno-Frontend Cross-Repo 자동 연동 설정" +echo "============================================" +echo "" + +# 색상 정의 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 현재 저장소 타입 확인 +echo -e "${BLUE}현재 저장소 타입을 선택하세요:${NC}" +echo "1) Bruno 저장소 (백엔드)" +echo "2) 프론트엔드 저장소" +echo "" +read -p "선택 (1 또는 2): " REPO_TYPE + +if [ "$REPO_TYPE" = "1" ]; then + echo "" + echo -e "${GREEN}=== Bruno 저장소 설정 ===${NC}" + echo "" + + # 프론트엔드 저장소 정보 입력 + read -p "프론트엔드 저장소 (예: myorg/frontend-repo): " FRONTEND_REPO + + # Workflow 파일 생성 + WORKFLOW_DIR=".github/workflows" + mkdir -p "$WORKFLOW_DIR" + + echo "" + echo -e "${BLUE}Workflow 파일 생성 중...${NC}" + + cat > "$WORKFLOW_DIR/notify-frontend.yml" << EOF +name: Notify Frontend on Bruno Changes + +on: + push: + branches: + - main + paths: + - 'bruno/**' + +jobs: + notify: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Notify Frontend Repository + run: | + curl -X POST \\ + -H "Accept: application/vnd.github+json" \\ + -H "Authorization: Bearer \${{ secrets.FRONTEND_REPO_TOKEN }}" \\ + https://api.github.com/repos/${FRONTEND_REPO}/dispatches \\ + -d '{ + "event_type": "bruno_updated", + "client_payload": { + "bruno_repo": "\${{ github.repository }}", + "commit_sha": "\${{ github.sha }}", + "commit_message": "\${{ github.event.head_commit.message }}", + "author": "\${{ github.event.head_commit.author.name }}" + } + }' + + - name: Notify Complete + run: | + echo "✅ Frontend repository notified!" + echo "🔗 Check: https://github.com/${FRONTEND_REPO}/actions" +EOF + + echo -e "${GREEN}✅ Workflow 파일 생성 완료: $WORKFLOW_DIR/notify-frontend.yml${NC}" + echo "" + echo -e "${YELLOW}⚠️ 다음 단계:${NC}" + echo "" + echo "1. GitHub Personal Access Token 생성" + echo " - https://github.com/settings/tokens" + echo " - 권한: repo, workflow" + echo "" + echo "2. Bruno 저장소 Settings → Secrets → Actions" + echo " - New repository secret 클릭" + echo " - Name: FRONTEND_REPO_TOKEN" + echo " - Value: 생성한 Token 붙여넣기" + echo "" + echo "3. Git Commit & Push" + echo " git add .github/workflows/notify-frontend.yml" + echo " git commit -m 'chore: add frontend notification workflow'" + echo " git push" + echo "" + +elif [ "$REPO_TYPE" = "2" ]; then + echo "" + echo -e "${GREEN}=== 프론트엔드 저장소 설정 ===${NC}" + echo "" + + # Bruno 저장소 정보 입력 + read -p "Bruno 저장소 (예: myorg/bruno-repo): " BRUNO_REPO + read -p "OpenAPI 출력 경로 (예: public/openapi.json): " OPENAPI_PATH + read -p "Swagger UI URL (예: https://myorg.github.io/myrepo): " SWAGGER_URL + + # Workflow 파일 생성 + WORKFLOW_DIR=".github/workflows" + mkdir -p "$WORKFLOW_DIR" + + echo "" + echo -e "${BLUE}Workflow 파일 생성 중...${NC}" + + # 디렉토리 경로 추출 + OPENAPI_DIR=$(dirname "$OPENAPI_PATH") + + cat > "$WORKFLOW_DIR/sync-bruno.yml" << EOF +name: Sync Bruno API Changes + +on: + repository_dispatch: + types: [bruno_updated] + workflow_dispatch: + +jobs: + sync: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + token: \${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Clone Bruno Repository + run: | + git clone https://github.com/${BRUNO_REPO}.git /tmp/bruno + + - name: Install Dependencies + run: npm install + + - name: Generate OpenAPI + run: | + mkdir -p ${OPENAPI_DIR} + + if [ -f ${OPENAPI_PATH} ]; then + cp ${OPENAPI_PATH} ${OPENAPI_PATH}.old + fi + + npx bruno-sync generate \\ + -i /tmp/bruno/bruno \\ + -o ${OPENAPI_PATH} \\ + --title "우리팀 API" \\ + --diff \\ + --changelog ${OPENAPI_DIR}/CHANGELOG.md + + npx bruno-sync generate \\ + -i /tmp/bruno/bruno \\ + -o ${OPENAPI_PATH} \\ + --diff \\ + --changelog ${OPENAPI_DIR}/changelog.html \\ + --changelog-format html + + - name: Check Changes + id: changes + run: | + git add ${OPENAPI_DIR}/ + if git diff --staged --quiet; then + echo "has_changes=false" >> \$GITHUB_OUTPUT + else + echo "has_changes=true" >> \$GITHUB_OUTPUT + if [ -f ${OPENAPI_DIR}/CHANGELOG.md ] && grep -q "Breaking" ${OPENAPI_DIR}/CHANGELOG.md; then + echo "has_breaking=true" >> \$GITHUB_OUTPUT + fi + fi + + - name: Create Pull Request + if: steps.changes.outputs.has_changes == 'true' + uses: peter-evans/create-pull-request@v5 + with: + commit-message: "chore: sync API spec from Bruno" + branch: api-sync-\${{ github.event.client_payload.commit_sha || 'manual' }} + title: "🔄 API 변경사항 동기화" + body: | + ## 🔄 Bruno API 변경사항 + + **Bruno Repository**: ${BRUNO_REPO} + **Commit**: \${{ github.event.client_payload.commit_sha || 'manual' }} + + \${{ steps.changes.outputs.has_breaking == 'true' && '### ⚠️ Breaking Changes 발견!' || '' }} + + ### 📝 확인하기 + - [OpenAPI Spec](../blob/\${{ github.ref_name }}/${OPENAPI_PATH}) + - [Changelog](../blob/\${{ github.ref_name }}/${OPENAPI_DIR}/CHANGELOG.md) + - [Swagger UI](${SWAGGER_URL}/api-viewer.html) + + ### ✅ 체크리스트 + - [ ] Breaking changes 확인 + - [ ] 빌드 테스트 + labels: api-sync,autogenerated +EOF + + echo -e "${GREEN}✅ Workflow 파일 생성 완료: $WORKFLOW_DIR/sync-bruno.yml${NC}" + echo "" + echo -e "${YELLOW}⚠️ 다음 단계:${NC}" + echo "" + echo "1. Git Commit & Push" + echo " git add .github/workflows/sync-bruno.yml" + echo " git commit -m 'chore: add Bruno sync workflow'" + echo " git push" + echo "" + echo "2. Bruno 저장소에서 설정 완료되면 자동으로 동작합니다!" + echo "" + +else + echo -e "${RED}잘못된 선택입니다.${NC}" + exit 1 +fi + +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}✅ 설정 완료!${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" +echo "📚 자세한 내용: docs/CROSS-REPO-SYNC.md" diff --git a/packages/bruno-api-typescript/src/cli/index.ts b/packages/bruno-api-typescript/src/cli/index.ts new file mode 100644 index 00000000..dd4d2ae7 --- /dev/null +++ b/packages/bruno-api-typescript/src/cli/index.ts @@ -0,0 +1,158 @@ +#!/usr/bin/env node + +/** + * bruno-api-typescript CLI + * Generate TypeScript API clients, typed definitions, and OpenAPI specs from Bruno files + */ + +import { Command } from 'commander'; +import { existsSync, writeFileSync, copyFileSync } from 'fs'; +import { resolve } from 'path'; +import { convertBrunoToOpenAPI } from '../converter/openapiConverter'; +import { detectChanges } from '../diff/changeDetector'; +import { generateChangelog, formatConsoleOutput, ChangelogFormat } from '../diff/changelogGenerator'; +import { generateHooks } from '../generator/index'; +import { BrunoHashCache } from '../generator/brunoHashCache'; + +const program = new Command(); + +program + .name('bruno-api') + .description('Generate TypeScript API clients, typed definitions, and OpenAPI specs from Bruno files') + .version('0.3.0'); + +program + .command('generate') + .description('Generate OpenAPI spec from Bruno collection') + .option('-i, --input ', 'Bruno collection directory', './bruno') + .option('-o, --output ', 'Output OpenAPI file', './openapi.json') + .option('--title ', 'API title', 'API Documentation') + .option('--version <version>', 'API version', '1.0.0') + .option('--description <description>', 'API description') + .option('--base-url <url>', 'Base URL for API') + .option('--diff', 'Detect changes from previous version', false) + .option('--changelog <path>', 'Generate changelog file') + .option( + '--changelog-format <format>', + 'Changelog format: markdown | json | html', + 'markdown' + ) + .option('--breaking-only', 'Show only breaking changes', false) + .action(async (options) => { + try { + const inputDir = resolve(process.cwd(), options.input); + const outputFile = resolve(process.cwd(), options.output); + + // 입력 디렉토리 확인 + if (!existsSync(inputDir)) { + console.error(`❌ Bruno directory not found: ${inputDir}`); + process.exit(1); + } + + console.log('🔄 Generating OpenAPI spec...'); + + // 이전 버전 백업 (diff 모드일 때) + let oldSpecPath: string | null = null; + if (options.diff && existsSync(outputFile)) { + oldSpecPath = outputFile + '.old'; + copyFileSync(outputFile, oldSpecPath); + } + + // OpenAPI 생성 + const spec = convertBrunoToOpenAPI(inputDir, { + title: options.title, + version: options.version, + description: options.description, + baseUrl: options.baseUrl, + }); + + // 파일 저장 + writeFileSync(outputFile, JSON.stringify(spec, null, 2), 'utf-8'); + console.log(`✅ OpenAPI spec generated: ${outputFile}`); + + // 변경사항 감지 + if (options.diff && oldSpecPath && existsSync(oldSpecPath)) { + console.log('\n🔍 Detecting changes...'); + + try { + const report = detectChanges(oldSpecPath, outputFile); + + // 콘솔 출력 + console.log(formatConsoleOutput(report, options.breakingOnly)); + + // Changelog 생성 + if (options.changelog) { + const changelogPath = resolve(process.cwd(), options.changelog); + const format = options.changelogFormat as ChangelogFormat; + + generateChangelog(report, { + format, + output: changelogPath, + breakingOnly: options.breakingOnly, + }); + } + + // Breaking changes가 있으면 exit code 1 + if (report.summary.breaking > 0 && options.breakingOnly) { + console.log( + '\n⚠️ Breaking changes detected! Please review the changes carefully.\n' + ); + process.exit(1); + } + } catch (error: any) { + console.warn(`⚠️ Failed to detect changes: ${error.message}`); + } + } + + console.log('\n✨ Done!\n'); + } catch (error: any) { + console.error(`❌ Error: ${error.message}`); + process.exit(1); + } + }); + +program + .command('generate-hooks') + .description('Generate typed API factories and definitions from Bruno collection') + .option('-i, --input <path>', 'Bruno collection directory', './bruno') + .option('-o, --output <path>', 'Output directory', './src/apis') + .option('--axios-path <path>', 'Axios instance import path', '@/utils/axiosInstance') + .option('--msw-output <path>', 'Output MSW handlers directory (optional)') + .option('--force', 'Force regenerate all clients (ignore hash cache)', false) + .option('--clear-cache', 'Clear hash cache before generation', false) + .action(async (options) => { + try { + const inputDir = resolve(process.cwd(), options.input); + const outputDir = resolve(process.cwd(), options.output); + const mswOutputDir = options.mswOutput ? resolve(process.cwd(), options.mswOutput) : undefined; + + if (!existsSync(inputDir)) { + console.error(`❌ Bruno directory not found: ${inputDir}`); + process.exit(1); + } + + if (options.clearCache) { + const cache = new BrunoHashCache(outputDir); + cache.clear(); + cache.save(); + console.log('🗑️ Hash cache cleared\n'); + } + + console.log('🏭 Generating typed API clients...\n'); + + await generateHooks({ + brunoDir: inputDir, + outputDir, + axiosInstancePath: options.axiosPath, + mswOutputDir, + force: options.force, + }); + + console.log('\n🎉 API clients generated successfully!'); + } catch (error: any) { + console.error(`❌ Error: ${error.message}`); + process.exit(1); + } + }); + +program.parse(process.argv); diff --git a/packages/bruno-api-typescript/src/converter/openapiConverter.ts b/packages/bruno-api-typescript/src/converter/openapiConverter.ts new file mode 100644 index 00000000..c0bf7734 --- /dev/null +++ b/packages/bruno-api-typescript/src/converter/openapiConverter.ts @@ -0,0 +1,245 @@ +/** + * Bruno 파일들을 OpenAPI 스펙으로 변환 + */ + +import { readdirSync, statSync } from 'fs'; +import { join, relative, dirname, basename } from 'path'; +import { parseBrunoFile, extractJsonFromDocs } from '../parser/bruParser'; +import { inferSchema } from './schemaBuilder'; + +export interface OpenAPISpec { + openapi: string; + info: { + title: string; + version: string; + description?: string; + }; + servers?: Array<{ + url: string; + description?: string; + }>; + paths: Record<string, any>; + components?: { + schemas?: Record<string, any>; + securitySchemes?: Record<string, any>; + }; + tags?: Array<{ + name: string; + description?: string; + }>; +} + +export interface ConversionOptions { + title?: string; + version?: string; + description?: string; + baseUrl?: string; +} + +/** + * Bruno 컬렉션을 OpenAPI로 변환 + */ +export function convertBrunoToOpenAPI( + brunoDir: string, + options: ConversionOptions = {} +): OpenAPISpec { + const spec: OpenAPISpec = { + openapi: '3.0.0', + info: { + title: options.title || 'API', + version: options.version || '1.0.0', + description: options.description, + }, + paths: {}, + components: { + schemas: {}, + }, + tags: [], + }; + + if (options.baseUrl) { + spec.servers = [{ url: options.baseUrl }]; + } + + // Bruno 파일들 수집 + const brunoFiles = collectBrunoFiles(brunoDir); + + // 도메인별로 그룹화 + const domainMap = new Map<string, any[]>(); + + for (const file of brunoFiles) { + try { + const parsed = parseBrunoFile(file); + const domain = extractDomain(file, brunoDir); + + if (!domainMap.has(domain)) { + domainMap.set(domain, []); + } + + domainMap.get(domain)!.push({ + file, + parsed, + }); + + // OpenAPI 경로 추가 + addPathToSpec(spec, parsed, domain); + } catch (error: any) { + console.warn(`Failed to parse ${file}:`, error.message); + } + } + + // 태그 추가 + for (const domain of domainMap.keys()) { + spec.tags!.push({ + name: domain, + description: `${domain} related endpoints`, + }); + } + + return spec; +} + +/** + * .bru 파일들 수집 + */ +function collectBrunoFiles(dir: string): string[] { + const files: string[] = []; + + function traverse(currentDir: string) { + const entries = readdirSync(currentDir); + + for (const entry of entries) { + const fullPath = join(currentDir, entry); + const stat = statSync(fullPath); + + if (stat.isDirectory()) { + traverse(fullPath); + } else if (entry.endsWith('.bru')) { + files.push(fullPath); + } + } + } + + traverse(dir); + return files; +} + +/** + * 파일 경로에서 도메인 추출 + * - "Solid Connection" 최상단 폴더를 제거하고 대괄호 패턴이 있는 첫 번째 폴더를 도메인으로 인식 + * - "숫자) 한글명 [영문키]" 형식: 1) 어드민 [Admin] → Admin + * - "한글명 [영문키]" 형식: 사용자 [users] → users + */ +function extractDomain(filePath: string, brunoDir: string): string { + const rel = relative(brunoDir, filePath); + const parts = rel.split('/'); + + // "Solid Connection" 폴더 제거 + const filteredParts = parts.filter(part => part !== 'Solid Connection'); + + // 대괄호 패턴이 있는 첫 번째 폴더 찾기 + const bracketPattern = /\[([^\]]+)\]/; + for (const part of filteredParts) { + const bracketMatch = part.match(bracketPattern); + if (bracketMatch) { + return bracketMatch[1].trim(); // 대괄호 안의 영문키 + } + } + + // 패턴이 없으면 파일이 있는 폴더명 사용 (마지막에서 두 번째) + return filteredParts[filteredParts.length - 2] || filteredParts[0] || 'default'; +} + +/** + * OpenAPI 스펙에 경로 추가 + */ +function addPathToSpec(spec: OpenAPISpec, parsed: any, domain: string): void { + const { method, url } = parsed.http; + const path = normalizeUrl(url); + + if (!spec.paths[path]) { + spec.paths[path] = {}; + } + + const operation: any = { + tags: [domain], + summary: parsed.meta.name || `${method} ${path}`, + operationId: generateOperationId(method, path, domain), + parameters: [], + responses: { + '200': { + description: 'Successful response', + }, + }, + }; + + // Headers + if (parsed.headers) { + for (const [key, value] of Object.entries(parsed.headers)) { + operation.parameters.push({ + name: key, + in: 'header', + required: false, + schema: { type: 'string' }, + example: value, + }); + } + } + + // Request body + if (parsed.body && parsed.body.content) { + try { + const bodyJson = JSON.parse(parsed.body.content); + operation.requestBody = { + required: true, + content: { + 'application/json': { + schema: inferSchema(bodyJson), + }, + }, + }; + } catch (error) { + // Invalid JSON + } + } + + // Response from docs + if (parsed.docs) { + const responseJson = extractJsonFromDocs(parsed.docs); + if (responseJson) { + operation.responses['200'] = { + description: 'Successful response', + content: { + 'application/json': { + schema: inferSchema(responseJson), + }, + }, + }; + } + } + + spec.paths[path][method.toLowerCase()] = operation; +} + +/** + * URL 정규화 (OpenAPI 경로 형식으로) + */ +function normalizeUrl(url: string): string { + // Query parameters 제거 + const withoutQuery = url.split('?')[0]; + + // :param -> {param} 변환 + return withoutQuery.replace(/:(\w+)/g, '{$1}'); +} + +/** + * Operation ID 생성 + */ +function generateOperationId(method: string, path: string, domain: string): string { + const cleanPath = path + .replace(/\{|\}/g, '') + .replace(/\//g, '-') + .replace(/^-|-$/g, ''); + + return `${method.toLowerCase()}-${domain}-${cleanPath}`; +} diff --git a/packages/bruno-api-typescript/src/converter/schemaBuilder.ts b/packages/bruno-api-typescript/src/converter/schemaBuilder.ts new file mode 100644 index 00000000..54abd6ab --- /dev/null +++ b/packages/bruno-api-typescript/src/converter/schemaBuilder.ts @@ -0,0 +1,75 @@ +/** + * JSON 샘플로부터 OpenAPI 스키마 생성 + */ + +export interface OpenAPISchema { + type: string; + properties?: Record<string, OpenAPISchema>; + items?: OpenAPISchema; + description?: string; + required?: string[]; + nullable?: boolean; + enum?: any[]; + example?: any; +} + +/** + * JSON 값으로부터 OpenAPI 스키마 생성 + */ +export function inferSchema(value: any): OpenAPISchema { + if (value === null) { + return { type: 'null', nullable: true }; + } + + if (Array.isArray(value)) { + if (value.length === 0) { + return { + type: 'array', + items: { type: 'object' }, + }; + } + return { + type: 'array', + items: inferSchema(value[0]), + }; + } + + const valueType = typeof value; + + switch (valueType) { + case 'string': + return { type: 'string', example: value }; + case 'number': + return { + type: Number.isInteger(value) ? 'integer' : 'number', + example: value, + }; + case 'boolean': + return { type: 'boolean', example: value }; + case 'object': + return inferObjectSchema(value); + default: + return { type: 'string' }; + } +} + +/** + * 객체로부터 스키마 생성 + */ +function inferObjectSchema(obj: Record<string, any>): OpenAPISchema { + const properties: Record<string, OpenAPISchema> = {}; + const required: string[] = []; + + for (const [key, value] of Object.entries(obj)) { + properties[key] = inferSchema(value); + if (value !== null && value !== undefined) { + required.push(key); + } + } + + return { + type: 'object', + properties, + required: required.length > 0 ? required : undefined, + }; +} diff --git a/packages/bruno-api-typescript/src/diff/changeDetector.ts b/packages/bruno-api-typescript/src/diff/changeDetector.ts new file mode 100644 index 00000000..e887a730 --- /dev/null +++ b/packages/bruno-api-typescript/src/diff/changeDetector.ts @@ -0,0 +1,350 @@ +/** + * API 변경사항 자동 감지 + * 이전 버전과 현재 버전의 OpenAPI 스펙을 비교하여 변경사항을 추출 + */ + +import { readFileSync, existsSync } from 'fs'; +import { OpenAPISpec } from '../converter/openapiConverter'; + +export type ChangeType = 'added' | 'removed' | 'modified'; +export type ChangeSeverity = 'breaking' | 'minor' | 'patch'; + +export interface FieldChange { + type: 'added' | 'removed' | 'type-changed' | 'required-changed'; + field: string; + path: string; + oldValue?: any; + newValue?: any; +} + +export interface EndpointChange { + type: ChangeType; + severity: ChangeSeverity; + domain: string; + path: string; + method: string; + changes?: FieldChange[]; + description: string; +} + +export interface ChangeReport { + timestamp: string; + summary: { + added: number; + removed: number; + modified: number; + breaking: number; + }; + changes: EndpointChange[]; +} + +/** + * 두 OpenAPI 스펙 간 변경사항 감지 + */ +export function detectChanges(oldSpecPath: string, newSpecPath: string): ChangeReport { + // 파일 존재 확인 + if (!existsSync(oldSpecPath)) { + throw new Error(`Old spec file not found: ${oldSpecPath}`); + } + if (!existsSync(newSpecPath)) { + throw new Error(`New spec file not found: ${newSpecPath}`); + } + + const oldSpec: OpenAPISpec = JSON.parse(readFileSync(oldSpecPath, 'utf-8')); + const newSpec: OpenAPISpec = JSON.parse(readFileSync(newSpecPath, 'utf-8')); + + const changes: EndpointChange[] = []; + + // 모든 경로와 메서드 수집 + const allPaths = new Set([ + ...Object.keys(oldSpec.paths || {}), + ...Object.keys(newSpec.paths || {}), + ]); + + for (const path of allPaths) { + const oldPath = oldSpec.paths?.[path]; + const newPath = newSpec.paths?.[path]; + + // 경로가 추가됨 + if (!oldPath && newPath) { + for (const method of Object.keys(newPath)) { + if (isHttpMethod(method)) { + changes.push({ + type: 'added', + severity: 'minor', + domain: extractDomain(newPath[method]), + path, + method: method.toUpperCase(), + description: `New endpoint: ${method.toUpperCase()} ${path}`, + }); + } + } + continue; + } + + // 경로가 제거됨 + if (oldPath && !newPath) { + for (const method of Object.keys(oldPath)) { + if (isHttpMethod(method)) { + changes.push({ + type: 'removed', + severity: 'breaking', + domain: extractDomain(oldPath[method]), + path, + method: method.toUpperCase(), + description: `Endpoint removed: ${method.toUpperCase()} ${path}`, + }); + } + } + continue; + } + + // 경로가 수정됨 - 메서드별로 비교 + if (oldPath && newPath) { + const allMethods = new Set([...Object.keys(oldPath), ...Object.keys(newPath)]); + + for (const method of allMethods) { + if (!isHttpMethod(method)) continue; + + const oldMethod = oldPath[method]; + const newMethod = newPath[method]; + + // 메서드가 추가됨 + if (!oldMethod && newMethod) { + changes.push({ + type: 'added', + severity: 'minor', + domain: extractDomain(newMethod), + path, + method: method.toUpperCase(), + description: `New method: ${method.toUpperCase()} ${path}`, + }); + continue; + } + + // 메서드가 제거됨 + if (oldMethod && !newMethod) { + changes.push({ + type: 'removed', + severity: 'breaking', + domain: extractDomain(oldMethod), + path, + method: method.toUpperCase(), + description: `Method removed: ${method.toUpperCase()} ${path}`, + }); + continue; + } + + // 메서드가 수정됨 - 스키마 비교 + if (oldMethod && newMethod) { + const fieldChanges = compareSchemas(oldMethod, newMethod); + + if (fieldChanges.length > 0) { + const hasBreaking = fieldChanges.some( + (fc) => fc.type === 'removed' || fc.type === 'type-changed' + ); + + changes.push({ + type: 'modified', + severity: hasBreaking ? 'breaking' : 'minor', + domain: extractDomain(newMethod), + path, + method: method.toUpperCase(), + changes: fieldChanges, + description: `Schema changed: ${method.toUpperCase()} ${path}`, + }); + } + } + } + } + } + + // 요약 계산 + const summary = { + added: changes.filter((c) => c.type === 'added').length, + removed: changes.filter((c) => c.type === 'removed').length, + modified: changes.filter((c) => c.type === 'modified').length, + breaking: changes.filter((c) => c.severity === 'breaking').length, + }; + + return { + timestamp: new Date().toISOString(), + summary, + changes, + }; +} + +/** + * HTTP 메서드 확인 + */ +function isHttpMethod(method: string): boolean { + const methods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options']; + return methods.includes(method.toLowerCase()); +} + +/** + * 도메인 추출 + * "한글명 [EnglishKey]" 형식에서 EnglishKey만 추출 + */ +function extractDomain(operation: any): string { + if (operation.tags && operation.tags.length > 0) { + const tag = operation.tags[0]; + + // 대괄호 안의 영문키 추출: 1) 어드민 [Admin] → Admin, 사용자 [users] → users + const bracketPattern = /\[([^\]]+)\]/; + const bracketMatch = tag.match(bracketPattern); + if (bracketMatch) { + return bracketMatch[1].trim(); // 대괄호 안의 영문키 + } + + return tag; + } + return 'default'; +} + +/** + * 두 operation의 스키마 비교 + */ +function compareSchemas(oldOp: any, newOp: any): FieldChange[] { + const changes: FieldChange[] = []; + + // Response 스키마 비교 (200 응답) + const oldResponse = oldOp.responses?.['200']?.content?.['application/json']?.schema; + const newResponse = newOp.responses?.['200']?.content?.['application/json']?.schema; + + if (oldResponse && newResponse) { + compareObjectSchemas('response', oldResponse, newResponse, changes); + } else if (!oldResponse && newResponse) { + changes.push({ + type: 'added', + field: 'response', + path: 'response', + newValue: 'object', + }); + } else if (oldResponse && !newResponse) { + changes.push({ + type: 'removed', + field: 'response', + path: 'response', + oldValue: 'object', + }); + } + + // Request body 비교 + const oldRequestBody = oldOp.requestBody?.content?.['application/json']?.schema; + const newRequestBody = newOp.requestBody?.content?.['application/json']?.schema; + + if (oldRequestBody && newRequestBody) { + compareObjectSchemas('requestBody', oldRequestBody, newRequestBody, changes); + } + + return changes; +} + +/** + * 객체 스키마 재귀적 비교 + */ +function compareObjectSchemas( + basePath: string, + oldSchema: any, + newSchema: any, + changes: FieldChange[] +): void { + // 타입이 다른 경우 + if (oldSchema.type !== newSchema.type) { + changes.push({ + type: 'type-changed', + field: basePath.split('.').pop() || basePath, + path: basePath, + oldValue: oldSchema.type, + newValue: newSchema.type, + }); + return; + } + + // 배열인 경우 - items 비교 + if (oldSchema.type === 'array' && newSchema.type === 'array') { + if (oldSchema.items && newSchema.items) { + compareObjectSchemas(`${basePath}[]`, oldSchema.items, newSchema.items, changes); + } + return; + } + + // 객체인 경우 - properties 비교 + if (oldSchema.type === 'object' && newSchema.type === 'object') { + const oldProps = oldSchema.properties || {}; + const newProps = newSchema.properties || {}; + + const allKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]); + + for (const key of allKeys) { + const oldProp = oldProps[key]; + const newProp = newProps[key]; + const fieldPath = `${basePath}.${key}`; + + // 필드가 추가됨 + if (!oldProp && newProp) { + changes.push({ + type: 'added', + field: key, + path: fieldPath, + newValue: newProp.type, + }); + continue; + } + + // 필드가 제거됨 + if (oldProp && !newProp) { + changes.push({ + type: 'removed', + field: key, + path: fieldPath, + oldValue: oldProp.type, + }); + continue; + } + + // 필드가 수정됨 + if (oldProp && newProp) { + // 타입 변경 + if (oldProp.type !== newProp.type) { + changes.push({ + type: 'type-changed', + field: key, + path: fieldPath, + oldValue: oldProp.type, + newValue: newProp.type, + }); + } + + // 중첩 객체/배열 재귀 비교 + if (oldProp.type === 'object' || oldProp.type === 'array') { + compareObjectSchemas(fieldPath, oldProp, newProp, changes); + } + } + } + } +} + +/** + * 변경사항이 Breaking인지 확인 + */ +export function isBreakingChange(change: EndpointChange): boolean { + return change.severity === 'breaking'; +} + +/** + * 도메인별로 변경사항 그룹화 + */ +export function groupChangesByDomain(changes: EndpointChange[]): Map<string, EndpointChange[]> { + const grouped = new Map<string, EndpointChange[]>(); + + for (const change of changes) { + if (!grouped.has(change.domain)) { + grouped.set(change.domain, []); + } + grouped.get(change.domain)!.push(change); + } + + return grouped; +} diff --git a/packages/bruno-api-typescript/src/diff/changelogGenerator.ts b/packages/bruno-api-typescript/src/diff/changelogGenerator.ts new file mode 100644 index 00000000..3903d9be --- /dev/null +++ b/packages/bruno-api-typescript/src/diff/changelogGenerator.ts @@ -0,0 +1,503 @@ +/** + * Changelog 자동 생성 + * Markdown, JSON, HTML 형식 지원 + */ + +import { writeFileSync } from 'fs'; +import { ChangeReport, EndpointChange, FieldChange, groupChangesByDomain } from './changeDetector'; + +export type ChangelogFormat = 'markdown' | 'json' | 'html'; + +export interface ChangelogOptions { + format?: ChangelogFormat; + output: string; + breakingOnly?: boolean; +} + +/** + * Changelog 생성 + */ +export function generateChangelog(report: ChangeReport, options: ChangelogOptions): void { + const format = options.format || 'markdown'; + + let content: string; + + switch (format) { + case 'markdown': + content = generateMarkdown(report, options.breakingOnly); + break; + case 'json': + content = generateJson(report, options.breakingOnly); + break; + case 'html': + content = generateHtml(report, options.breakingOnly); + break; + default: + throw new Error(`Unsupported format: ${format}`); + } + + writeFileSync(options.output, content, 'utf-8'); + console.log(`✅ Changelog generated: ${options.output}`); +} + +/** + * Markdown 형식 생성 + */ +function generateMarkdown(report: ChangeReport, breakingOnly?: boolean): string { + const lines: string[] = []; + + lines.push('# API Changelog\n'); + lines.push(`**Generated**: ${new Date(report.timestamp).toLocaleString()}\n`); + + // 요약 + lines.push('## 📊 Summary\n'); + lines.push('| Type | Count |'); + lines.push('|------|-------|'); + lines.push(`| ✨ Added | ${report.summary.added} |`); + lines.push(`| 🗑️ Removed | ${report.summary.removed} |`); + lines.push(`| 🔄 Modified | ${report.summary.modified} |`); + lines.push(`| ⚠️ **Breaking Changes** | **${report.summary.breaking}** |\n`); + + // 변경사항 필터링 + let changes = report.changes; + if (breakingOnly) { + changes = changes.filter((c) => c.severity === 'breaking'); + } + + if (changes.length === 0) { + lines.push('_No changes detected._\n'); + return lines.join('\n'); + } + + // Breaking changes 섹션 + const breakingChanges = changes.filter((c) => c.severity === 'breaking'); + if (breakingChanges.length > 0) { + lines.push('## ⚠️ Breaking Changes\n'); + lines.push('> **주의**: 이 변경사항들은 기존 코드를 깨뜨릴 수 있습니다!\n'); + + for (const change of breakingChanges) { + lines.push(`#### ⚠️ \`${change.method} ${change.path}\`\n`); + + if (change.changes && change.changes.length > 0) { + lines.push('**변경사항**:\n'); + for (const fc of change.changes) { + lines.push(`- ${formatFieldChange(fc)}`); + } + lines.push(''); + + // 마이그레이션 가이드 + lines.push('**마이그레이션 가이드**:\n'); + lines.push('```typescript'); + lines.push('// Before'); + for (const fc of change.changes) { + if (fc.type === 'removed') { + lines.push(`// ${fc.path} // ❌ This field no longer exists`); + } else if (fc.type === 'type-changed') { + lines.push(`// ${fc.path}: ${fc.oldValue}`); + } + } + lines.push(''); + lines.push('// After'); + for (const fc of change.changes) { + if (fc.type === 'type-changed') { + lines.push(`// ${fc.path}: ${fc.newValue} // ⚠️ Type changed!`); + } + } + lines.push('```\n'); + } else { + lines.push(`${change.description}\n`); + } + } + } + + // 도메인별로 그룹화 + const grouped = groupChangesByDomain(changes); + + for (const [domain, domainChanges] of grouped.entries()) { + lines.push(`## 📁 ${domain.charAt(0).toUpperCase() + domain.slice(1)}\n`); + + // Added + const added = domainChanges.filter((c) => c.type === 'added'); + if (added.length > 0) { + lines.push('### ✨ Added\n'); + for (const change of added) { + lines.push(`#### ✨ \`${change.method} ${change.path}\`\n`); + lines.push(`${change.description}\n`); + } + } + + // Modified (non-breaking) + const modified = domainChanges.filter( + (c) => c.type === 'modified' && c.severity !== 'breaking' + ); + if (modified.length > 0) { + lines.push('### 🔄 Modified\n'); + for (const change of modified) { + lines.push(`#### 🔄 \`${change.method} ${change.path}\`\n`); + + if (change.changes && change.changes.length > 0) { + lines.push('**변경사항**:\n'); + for (const fc of change.changes) { + lines.push(`- ${formatFieldChange(fc)}`); + } + lines.push(''); + } + } + } + + // Removed + const removed = domainChanges.filter((c) => c.type === 'removed'); + if (removed.length > 0) { + lines.push('### 🗑️ Removed\n'); + for (const change of removed) { + lines.push(`#### 🗑️ \`${change.method} ${change.path}\`\n`); + lines.push(`${change.description}\n`); + } + } + } + + return lines.join('\n'); +} + +/** + * JSON 형식 생성 + */ +function generateJson(report: ChangeReport, breakingOnly?: boolean): string { + let changes = report.changes; + if (breakingOnly) { + changes = changes.filter((c) => c.severity === 'breaking'); + } + + return JSON.stringify( + { + ...report, + changes, + }, + null, + 2 + ); +} + +/** + * HTML 형식 생성 + */ +function generateHtml(report: ChangeReport, breakingOnly?: boolean): string { + let changes = report.changes; + if (breakingOnly) { + changes = changes.filter((c) => c.severity === 'breaking'); + } + + const html = `<!DOCTYPE html> +<html lang="ko"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>API Changelog + + + +
+

🔍 API Changelog

+
Generated: ${new Date(report.timestamp).toLocaleString()}
+ +
+
+

✨ Added

+
${report.summary.added}
+
+
+

🔄 Modified

+
${report.summary.modified}
+
+
+

🗑️ Removed

+
${report.summary.removed}
+
+
+

⚠️ Breaking

+
${report.summary.breaking}
+
+
+ + ${generateHtmlChanges(changes)} +
+ +`; + + return html; +} + +/** + * HTML 변경사항 섹션 생성 + */ +function generateHtmlChanges(changes: EndpointChange[]): string { + const grouped = groupChangesByDomain(changes); + const sections: string[] = []; + + for (const [domain, domainChanges] of grouped.entries()) { + sections.push(`
`); + sections.push(`

📁 ${domain.charAt(0).toUpperCase() + domain.slice(1)}

`); + + for (const change of domainChanges) { + const className = change.severity === 'breaking' ? 'breaking' : change.type; + sections.push(`
`); + sections.push(`
`); + sections.push( + `${change.method}` + ); + sections.push(`${change.path}`); + sections.push(`
`); + + if (change.changes && change.changes.length > 0) { + sections.push(`
`); + for (const fc of change.changes) { + const fcClass = + fc.type === 'added' ? 'added' : fc.type === 'removed' ? 'removed' : 'modified'; + sections.push(`
`); + sections.push(formatFieldChange(fc)); + sections.push(`
`); + } + sections.push(`
`); + } + + sections.push(`
`); + } + + sections.push(`
`); + } + + return sections.join('\n'); +} + +/** + * 필드 변경사항 포맷팅 + */ +function formatFieldChange(fc: FieldChange): string { + switch (fc.type) { + case 'added': + return `✨ Added: ${fc.path} (${fc.newValue})`; + case 'removed': + return `🗑️ Removed: ${fc.path} (was ${fc.oldValue})`; + case 'type-changed': + return `🔄 Type changed: ${fc.path} from ${fc.oldValue} to ${fc.newValue}`; + case 'required-changed': + return `📝 Required changed: ${fc.path}`; + default: + return `Modified: ${fc.path}`; + } +} + +/** + * CLI 콘솔 출력용 포맷팅 + */ +export function formatConsoleOutput(report: ChangeReport, breakingOnly?: boolean): string { + const lines: string[] = []; + + lines.push('\n🔍 API Changes Detected\n'); + + // 요약 + lines.push('📊 Summary:'); + lines.push(` ✨ Added: ${report.summary.added}`); + lines.push(` 🗑️ Removed: ${report.summary.removed}`); + lines.push(` 🔄 Modified: ${report.summary.modified}`); + if (report.summary.breaking > 0) { + lines.push(` ⚠️ **BREAKING CHANGES**: ${report.summary.breaking}`); + } + lines.push(''); + + // 변경사항 필터링 + let changes = report.changes; + if (breakingOnly) { + changes = changes.filter((c) => c.severity === 'breaking'); + } + + if (changes.length === 0) { + lines.push('No changes detected.'); + return lines.join('\n'); + } + + lines.push('📝 Detailed Changes:\n'); + + // Breaking changes 먼저 + const breaking = changes.filter((c) => c.severity === 'breaking'); + if (breaking.length > 0) { + lines.push('⚠️ BREAKING CHANGES:'); + for (const change of breaking) { + lines.push(` ${change.method.padEnd(6)} ${change.path}`); + if (change.changes) { + for (const fc of change.changes) { + const symbol = fc.type === 'removed' ? '-' : fc.type === 'added' ? '+' : '~'; + lines.push(` ${symbol} ${fc.path}${formatFieldChangeShort(fc)}`); + } + } + } + lines.push(''); + } + + // Added + const added = changes.filter((c) => c.type === 'added'); + if (added.length > 0) { + lines.push('✨ Added:'); + for (const change of added) { + lines.push(` ${change.method.padEnd(6)} ${change.path}`); + } + lines.push(''); + } + + // Modified (non-breaking) + const modified = changes.filter((c) => c.type === 'modified' && c.severity !== 'breaking'); + if (modified.length > 0) { + lines.push('🔄 Modified:'); + for (const change of modified) { + lines.push(` ${change.method.padEnd(6)} ${change.path}`); + if (change.changes) { + for (const fc of change.changes) { + const symbol = fc.type === 'removed' ? '-' : fc.type === 'added' ? '+' : '~'; + lines.push(` ${symbol} ${fc.path}${formatFieldChangeShort(fc)}`); + } + } + } + lines.push(''); + } + + // Removed + const removed = changes.filter((c) => c.type === 'removed'); + if (removed.length > 0) { + lines.push('🗑️ Removed:'); + for (const change of removed) { + lines.push(` ${change.method.padEnd(6)} ${change.path}`); + } + lines.push(''); + } + + return lines.join('\n'); +} + +/** + * 필드 변경사항 짧은 포맷 + */ +function formatFieldChangeShort(fc: FieldChange): string { + if (fc.type === 'type-changed') { + return ` (${fc.oldValue} → ${fc.newValue})`; + } + return ''; +} diff --git a/packages/bruno-api-typescript/src/generator/apiClientGenerator.ts b/packages/bruno-api-typescript/src/generator/apiClientGenerator.ts new file mode 100644 index 00000000..229d0d8b --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/apiClientGenerator.ts @@ -0,0 +1,121 @@ +/** + * Axios API 클라이언트 생성기 + * Bruno 파일로부터 axios API 호출 함수 생성 + */ + +import { ParsedBrunoFile } from '../parser/bruParser'; +import { extractJsonFromDocs } from '../parser/bruParser'; +import { generateTypeScriptInterface, urlToFunctionName, functionNameToTypeName, toCamelCase } from './typeGenerator'; + +export interface ApiFunction { + name: string; + method: string; + url: string; + responseType: string; + requestType?: string; + hasParams: boolean; + hasBody: boolean; +} + +/** + * Bruno 파일로부터 API 함수 정보 추출 + */ +export function extractApiFunction(parsed: ParsedBrunoFile, filePath: string): ApiFunction | null { + const { http, meta } = parsed; + + if (!http.method || !http.url) { + return null; + } + + // .bru 파일명에서 함수명 생성 + let fileName = filePath.split('/').pop()?.replace('.bru', '') || ''; + + // 한글명 [영문키] 패턴 추출: 멘토 목록 조회 [mentor-list] → mentor-list + const bracketPattern = /\[([^\]]+)\]/; + const bracketMatch = fileName.match(bracketPattern); + if (bracketMatch) { + fileName = bracketMatch[1].trim(); // 대괄호 안의 영문키만 사용 + } + + const baseFunctionName = toCamelCase(fileName); + // HTTP 메서드 prefix 추가: signOut → postSignOut + const methodPrefix = http.method.toLowerCase(); + const functionName = `${methodPrefix}${baseFunctionName.charAt(0).toUpperCase()}${baseFunctionName.slice(1)}`; + const responseType = functionNameToTypeName(baseFunctionName); + + // URL에 파라미터가 있는지 확인 + const hasParams = http.url.includes(':') || http.url.includes('{'); + + // POST, PUT, PATCH는 body를 가질 수 있음 + const hasBody = ['POST', 'PUT', 'PATCH'].includes(http.method.toUpperCase()); + + return { + name: functionName, + method: http.method.toUpperCase(), + url: http.url, + responseType, + hasParams, + hasBody, + }; +} + +/** + * API 함수 코드 생성 + */ +export function generateApiFunction(apiFunc: ApiFunction, domain: string): string { + const { name, method, url, responseType, hasParams, hasBody } = apiFunc; + + const lines: string[] = []; + + // 파라미터 인터페이스 생성 + const paramsList: string[] = []; + const urlParams: string[] = []; + + // URL 파라미터 추출 + const urlParamMatches = url.matchAll(/:(\w+)|\{(\w+)\}/g); + for (const match of urlParamMatches) { + const paramName = match[1] || match[2]; + urlParams.push(paramName); + paramsList.push(`${paramName}: string | number`); + } + + // Query 파라미터 + if (method === 'GET') { + paramsList.push('params?: Record'); + } + + // Body 파라미터 + if (hasBody) { + paramsList.push(`data?: ${responseType.replace('Response', 'Request')}`); + } + + // 함수 시그니처 + const paramsStr = paramsList.length > 0 ? `{ ${paramsList.join(', ')} }` : ''; + const paramsType = paramsList.length > 0 ? `params: ${paramsStr}` : ''; + + // URL 생성 로직 + let urlExpression = `\`${url}\``; + for (const param of urlParams) { + urlExpression = urlExpression.replace(`:${param}`, `\${params.${param}}`); + urlExpression = urlExpression.replace(`{${param}}`, `\${params.${param}}`); + } + + // 함수 생성 + lines.push(`const ${name} = async (${paramsType}): Promise<${responseType}> => {`); + + const configParts: string[] = []; + if (method === 'GET' && paramsList.some(p => p.includes('params?'))) { + configParts.push('params: params?.params'); + } + + const configStr = configParts.length > 0 ? `, { ${configParts.join(', ')} }` : ''; + const bodyStr = hasBody ? ', params?.data' : ''; + + lines.push(` const res = await axiosInstance.${method.toLowerCase()}<${responseType}>(`); + lines.push(` ${urlExpression}${bodyStr}${configStr}`); + lines.push(` );`); + lines.push(` return res.data;`); + lines.push(`};`); + + return lines.join('\n'); +} diff --git a/packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts b/packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts new file mode 100644 index 00000000..d9ed2795 --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/apiDefinitionGenerator.ts @@ -0,0 +1,137 @@ +/** + * API Definition Generator + * Generates typed API metadata definitions from Bruno files + */ + +import { ParsedBrunoFile } from '../parser/bruParser'; +import { ApiFunction } from './apiClientGenerator'; +import { toCamelCase } from './typeGenerator'; + +export interface ApiDefinitionMeta { + method: string; + path: string; + pathParams: string; + queryParams: string; + body: string; + response: string; +} + +function toPascalCase(value: string): string { + const camel = toCamelCase(value); + return `${camel.charAt(0).toUpperCase()}${camel.slice(1)}`; +} + +/** + * Extract URL parameters from a path + */ +function extractPathParams(url: string): string[] { + const params: string[] = []; + + let processedUrl = url.replace(/\{\{URL\}\}/g, ''); + + const brunoVarPattern = /\{\{([^}]+)\}\}/g; + let match; + while ((match = brunoVarPattern.exec(processedUrl)) !== null) { + const varName = match[1]; + if (varName === 'URL') continue; + const camelVarName = varName.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + if (!params.includes(camelVarName)) { + params.push(camelVarName); + } + } + + const urlParamMatches = processedUrl.matchAll(/:(\w+)|\{(\w+)\}/g); + for (const match of urlParamMatches) { + const paramName = match[1] || match[2]; + if (!params.includes(paramName)) { + params.push(paramName); + } + } + + return params; +} + +/** + * Generate API definition metadata for a single API function + */ +export function generateApiDefinitionMeta( + apiFunc: ApiFunction, + parsed: ParsedBrunoFile +): ApiDefinitionMeta { + const { method, url, responseType } = apiFunc; + const pathParams = extractPathParams(url); + + const pathParamsType = pathParams.length > 0 + ? `{ ${pathParams.map(p => `${p}: string | number`).join('; ')} }` + : 'Record'; + + const queryParamsType = method === 'GET' + ? 'Record' + : 'Record'; + + const requestType = responseType.replace('Response', 'Request'); + const hasBody = ['POST', 'PUT', 'PATCH'].includes(method) && Boolean(parsed.body?.content?.trim()); + const bodyType = hasBody ? requestType : 'Record'; + + return { + method, + path: url, + pathParams: pathParamsType, + queryParams: queryParamsType, + body: bodyType, + response: responseType, + }; +} + +/** + * Generate apiDefinitions.ts file content + */ +export function generateApiDefinitionsFile( + apiFunctions: Array<{ apiFunc: ApiFunction; parsed: ParsedBrunoFile }>, + domain: string +): string { + const lines: string[] = []; + + const typeNames = new Set(); + + for (const { apiFunc, parsed } of apiFunctions) { + const meta = generateApiDefinitionMeta(apiFunc, parsed); + + if (meta.response !== 'void') { + typeNames.add(meta.response); + } + if (meta.body !== 'Record') { + typeNames.add(meta.body); + } + } + + const sortedTypes = Array.from(typeNames).sort(); + if (sortedTypes.length > 0) { + lines.push(`import type { ${sortedTypes.join(', ')} } from './api';`); + lines.push(''); + } + + const definitionsConstName = `${toCamelCase(domain)}ApiDefinitions`; + const definitionsTypeName = `${toPascalCase(domain)}ApiDefinitions`; + lines.push(`export const ${definitionsConstName} = {`); + + for (const { apiFunc, parsed } of apiFunctions) { + const meta = generateApiDefinitionMeta(apiFunc, parsed); + + lines.push(` ${apiFunc.name}: {`); + lines.push(` method: '${meta.method}' as const,`); + lines.push(` path: '${meta.path}' as const,`); + lines.push(` pathParams: {} as ${meta.pathParams},`); + lines.push(` queryParams: {} as ${meta.queryParams},`); + lines.push(` body: {} as ${meta.body},`); + lines.push(` response: {} as ${meta.response},`); + lines.push(` },`); + } + + lines.push('} as const;'); + lines.push(''); + + lines.push(`export type ${definitionsTypeName} = typeof ${definitionsConstName};`); + + return lines.join('\n'); +} diff --git a/packages/bruno-api-typescript/src/generator/apiFactoryGenerator.ts b/packages/bruno-api-typescript/src/generator/apiFactoryGenerator.ts new file mode 100644 index 00000000..110df6e8 --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/apiFactoryGenerator.ts @@ -0,0 +1,221 @@ +/** + * API 팩토리 생성기 + * 도메인별로 모든 API 함수를 객체로 묶어서 export + */ + +import { ParsedBrunoFile, extractJsonFromDocs } from '../parser/bruParser'; +import { ApiFunction } from './apiClientGenerator'; +import { generateTypeScriptInterface, toCamelCase, functionNameToTypeName } from './typeGenerator'; + +/** + * 빈 인터페이스를 Record 타입으로 변환 + */ +function convertEmptyInterfaceToType(content: string, typeName: string): string { + // 빈 인터페이스 패턴: export interface TypeName { } + const emptyInterfacePattern = new RegExp(`export interface ${typeName}\\s*\\{\\s*\\}`); + if (emptyInterfacePattern.test(content)) { + return `export type ${typeName} = Record;`; + } + return content; +} + +/** + * 팩토리용 API 함수 코드 생성 (객체 속성으로 사용) + */ +function generateApiFunctionForFactory(apiFunc: ApiFunction, parsed: ParsedBrunoFile): string { + const { name, method, url, responseType, hasParams, hasBody } = apiFunc; + + const lines: string[] = []; + + // 파라미터 인터페이스 생성 + const paramsList: string[] = []; + const urlParams: string[] = []; + + // URL 생성 로직 + // 1. {{URL}} 제거 + let processedUrl = url.replace(/\{\{URL\}\}/g, ''); + + // 2. 브루노 변수 {{변수명}} 처리 (URL 파라미터로 변환) + const brunoVarPattern = /\{\{([^}]+)\}\}/g; + let match; + const processedBrunoVars = new Set(); + + while ((match = brunoVarPattern.exec(processedUrl)) !== null) { + const varName = match[1]; + // URL 변수는 제외 + if (varName === 'URL') continue; + + const camelVarName = varName.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + if (!urlParams.includes(camelVarName) && !processedBrunoVars.has(camelVarName)) { + urlParams.push(camelVarName); + paramsList.push(`${camelVarName}: string | number`); + processedBrunoVars.add(camelVarName); + } + processedUrl = processedUrl.replace(match[0], `\${params.${camelVarName}}`); + } + + // 3. 기존 URL 파라미터 패턴 처리 (:param, {param}) + const urlParamMatches = processedUrl.matchAll(/:(\w+)|\{(\w+)\}/g); + for (const match of urlParamMatches) { + const paramName = match[1] || match[2]; + if (!urlParams.includes(paramName) && !processedBrunoVars.has(paramName)) { + urlParams.push(paramName); + paramsList.push(`${paramName}: string | number`); + } + processedUrl = processedUrl.replace(`:${paramName}`, `\${params.${paramName}}`); + processedUrl = processedUrl.replace(`{${paramName}}`, `\${params.${paramName}}`); + } + + // Query 파라미터 + if (method === 'GET') { + paramsList.push('params?: Record'); + } + + // Body 파라미터 + if (hasBody) { + paramsList.push(`data?: ${responseType.replace('Response', 'Request')}`); + } + + // 함수 시그니처 + const paramsStr = paramsList.length > 0 ? `{ ${paramsList.join(', ')} }` : ''; + const paramsType = paramsList.length > 0 ? `params: ${paramsStr}` : ''; + + let urlExpression = `\`${processedUrl}\``; + + // 함수 생성 (화살표 함수로) + lines.push(`async (${paramsType}): Promise<${responseType}> => {`); + + const configParts: string[] = []; + if (method === 'GET' && paramsList.some(p => p.includes('params?'))) { + configParts.push('params: params?.params'); + } + + const configStr = configParts.length > 0 ? `, { ${configParts.join(', ')} }` : ''; + const bodyStr = hasBody ? ', params?.data' : ''; + + lines.push(` const res = await axiosInstance.${method.toLowerCase()}<${responseType}>(`); + lines.push(` ${urlExpression}${bodyStr}${configStr}`); + lines.push(` );`); + lines.push(` return res.data;`); + lines.push(`}`); + + return lines.join('\n'); +} + +/** + * 도메인별 API 팩토리 파일 생성 + */ +export function generateApiFactory( + apiFunctions: Array<{ apiFunc: ApiFunction; parsed: ParsedBrunoFile }>, + domain: string, + axiosInstancePath: string +): string { + const lines: string[] = [ + `import { axiosInstance } from "${axiosInstancePath}";`, + '', + ]; + + // 모든 타입 정의 수집 + const typeDefinitions = new Set(); + + for (const { apiFunc, parsed } of apiFunctions) { + const { responseType } = apiFunc; + const requestType = responseType.replace('Response', 'Request'); + + // Response 타입 생성 + if (parsed.docs) { + const jsonData = extractJsonFromDocs(parsed.docs); + if (jsonData !== null && jsonData !== undefined) { + // 빈 객체 체크 + if (typeof jsonData === 'object' && !Array.isArray(jsonData) && Object.keys(jsonData).length === 0) { + // 빈 객체인 경우 Record 타입 생성 + const emptyType = `export type ${responseType} = Record;`; + if (!typeDefinitions.has(emptyType)) { + typeDefinitions.add(emptyType); + lines.push(emptyType); + lines.push(''); + } + } else { + const typeDefs = generateTypeScriptInterface(jsonData, responseType); + for (const typeDef of typeDefs) { + // 빈 인터페이스 체크 및 변환 + const processedContent = convertEmptyInterfaceToType(typeDef.content, responseType); + if (!typeDefinitions.has(processedContent)) { + typeDefinitions.add(processedContent); + lines.push(processedContent); + lines.push(''); + } + } + } + } else { + // JSON 추출 실패 시 void 타입 생성 + const defaultType = `export type ${responseType} = void;`; + if (!typeDefinitions.has(defaultType)) { + typeDefinitions.add(defaultType); + lines.push(defaultType); + lines.push(''); + } + } + } else { + // Response가 없으면 void 타입 사용 + const defaultType = `export type ${responseType} = void;`; + if (!typeDefinitions.has(defaultType)) { + typeDefinitions.add(defaultType); + lines.push(defaultType); + lines.push(''); + } + } + + // Request 타입 생성 (POST, PUT, PATCH인 경우) + if (['POST', 'PUT', 'PATCH'].includes(apiFunc.method)) { + if (parsed.body?.content) { + try { + const bodyData = JSON.parse(parsed.body.content); + const requestTypeDefs = generateTypeScriptInterface(bodyData, requestType); + for (const typeDef of requestTypeDefs) { + if (!typeDefinitions.has(typeDef.content)) { + typeDefinitions.add(typeDef.content); + lines.push(typeDef.content); + lines.push(''); + } + } + } catch { + // Request body 파싱 실패시 Record 사용 + const defaultRequestType = `export type ${requestType} = Record;`; + if (!typeDefinitions.has(defaultRequestType)) { + typeDefinitions.add(defaultRequestType); + lines.push(defaultRequestType); + lines.push(''); + } + } + } else { + // Request body가 없으면 Record 사용 + const defaultRequestType = `export type ${requestType} = Record;`; + if (!typeDefinitions.has(defaultRequestType)) { + typeDefinitions.add(defaultRequestType); + lines.push(defaultRequestType); + lines.push(''); + } + } + } + } + + // 팩토리 객체 생성 + const factoryName = `${toCamelCase(domain)}Api`; + lines.push(`export const ${factoryName} = {`); + + for (const { apiFunc, parsed } of apiFunctions) { + const functionCode = generateApiFunctionForFactory(apiFunc, parsed); + // 들여쓰기 추가 (2칸) + const indentedCode = functionCode.split('\n').map((line, index) => { + if (index === 0) return ` ${apiFunc.name}: ${line}`; + return ` ${line}`; + }).join('\n'); + lines.push(indentedCode + ','); + lines.push(''); + } + + lines.push(`};`); + + return lines.join('\n'); +} diff --git a/packages/bruno-api-typescript/src/generator/brunoHashCache.ts b/packages/bruno-api-typescript/src/generator/brunoHashCache.ts new file mode 100644 index 00000000..fa14e928 --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/brunoHashCache.ts @@ -0,0 +1,173 @@ +import { createHash } from 'crypto'; +import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; +import { join } from 'path'; + +export interface HashEntry { + hash: string; + lastGenerated: string; + outputFiles: string[]; +} + +export interface HashCache { + version: string; + hashes: Record; +} + +export class BrunoHashCache { + private cachePath: string; + private cacheDir: string; + private cache: HashCache; + + constructor(outputDir: string) { + this.cacheDir = join(outputDir, '.bruno-cache'); + this.cachePath = join(this.cacheDir, 'hashes.json'); + this.cache = { version: '1.0', hashes: {} }; + } + + /** + * 캐시 파일 로드 + */ + load(): void { + if (existsSync(this.cachePath)) { + try { + const content = readFileSync(this.cachePath, 'utf-8'); + this.cache = JSON.parse(content); + } catch (error) { + console.warn('⚠️ Failed to load hash cache, using empty cache'); + this.cache = { version: '1.0', hashes: {} }; + } + } else { + this.cache = { version: '1.0', hashes: {} }; + } + } + + /** + * 캐시 파일 저장 + */ + save(): void { + try { + mkdirSync(this.cacheDir, { recursive: true }); + writeFileSync( + this.cachePath, + JSON.stringify(this.cache, null, 2), + 'utf-8' + ); + } catch (error) { + console.error('❌ Failed to save hash cache:', error); + } + } + + /** + * Bruno 파일의 SHA-256 해시 계산 + * 개행 문자를 정규화하여 OS 간 차이를 방지합니다. + * + * @param brunoFilePath - Bruno 파일의 절대 경로 + * @returns 64자 hex string SHA-256 해시 + */ + calculateHash(brunoFilePath: string): string { + const content = readFileSync(brunoFilePath, 'utf-8'); + // 개행 문자 정규화 (Windows/Unix 호환성) + const normalized = content.replace(/\r\n/g, '\n').trim(); + return createHash('sha256').update(normalized, 'utf-8').digest('hex'); + } + + /** + * 이전 해시 조회 + */ + getHash(brunoFilePath: string): string | null { + return this.cache.hashes[brunoFilePath]?.hash || null; + } + + /** + * 해시 저장 + */ + setHash(brunoFilePath: string, hash: string, outputFiles: string[]): void { + this.cache.hashes[brunoFilePath] = { + hash, + lastGenerated: new Date().toISOString(), + outputFiles, + }; + } + + /** + * Bruno 파일 변경 여부 확인 + */ + hasChanged(brunoFilePath: string): boolean { + // 1. 이전 해시 조회 + const previousHash = this.getHash(brunoFilePath); + + // 2. 캐시가 없으면 변경됨으로 간주 (첫 실행) + if (!previousHash) { + return true; + } + + // 3. 출력 파일 체크 (outputFiles가 빈 배열인 경우는 파싱 실패로 스킵) + const entry = this.cache.hashes[brunoFilePath]; + if (entry && entry.outputFiles && entry.outputFiles.length > 0) { + // 출력 파일이 있는 경우에만 존재 여부 확인 + if (!this.hasOutputFile(brunoFilePath)) { + return true; // 파일이 삭제됨 + } + } + // outputFiles가 빈 배열이면 파싱 실패 케이스이므로 파일 체크 스킵 + + // 4. 현재 해시 계산 및 비교 + const currentHash = this.calculateHash(brunoFilePath); + return currentHash !== previousHash; + } + + /** + * 출력 파일 존재 여부 확인 + */ + hasOutputFile(brunoFilePath: string): boolean { + const entry = this.cache.hashes[brunoFilePath]; + if (!entry || !entry.outputFiles || entry.outputFiles.length === 0) { + return false; + } + // 하나라도 존재하면 true + return entry.outputFiles.some(f => existsSync(f)); + } + + /** + * 캐시 초기화 + */ + clear(): void { + this.cache = { version: '1.0', hashes: {} }; + } + + /** + * 삭제된 Bruno 파일의 캐시 정리 + */ + cleanup(): void { + const brunoFiles = Object.keys(this.cache.hashes); + let cleanedCount = 0; + + for (const brunoPath of brunoFiles) { + if (!existsSync(brunoPath)) { + delete this.cache.hashes[brunoPath]; + cleanedCount++; + } + } + + if (cleanedCount > 0) { + console.log(`🗑️ Cleaned up ${cleanedCount} deleted file(s) from cache`); + } + } + + /** + * 캐시 경로 반환 (로깅용) + */ + getCachePath(): string { + return this.cachePath; + } + + /** + * 통계 정보 반환 + */ + getStats(): { total: number; cached: number } { + return { + total: 0, // generateHooks에서 설정 + cached: Object.keys(this.cache.hashes).length, + }; + } +} diff --git a/packages/bruno-api-typescript/src/generator/index.ts b/packages/bruno-api-typescript/src/generator/index.ts new file mode 100644 index 00000000..b0cb3d6c --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/index.ts @@ -0,0 +1,326 @@ +/** + * API 생성 메인 로직 + * Bruno 파일들을 읽어서 API 팩토리 및 타입 정의를 생성 + */ + +import { readdirSync, statSync, mkdirSync, writeFileSync, existsSync } from 'fs'; +import { join, relative, dirname } from 'path'; +import { parseBrunoFile } from '../parser/bruParser'; +import { extractApiFunction } from './apiClientGenerator'; +import { generateMSWHandler, generateDomainHandlersIndex, generateMSWIndex } from './mswGenerator'; +import { generateApiFactory } from './apiFactoryGenerator'; +import { generateApiDefinitionsFile } from './apiDefinitionGenerator'; +import { BrunoHashCache } from './brunoHashCache'; +import { toCamelCase } from './typeGenerator'; + +export interface GenerateHooksOptions { + brunoDir: string; + outputDir: string; + axiosInstancePath?: string; + mswOutputDir?: string; + force?: boolean; +} + +/** + * Bruno 디렉토리에서 모든 .bru 파일 찾기 + */ +function findBrunoFiles(dir: string): string[] { + const files: string[] = []; + + function traverse(currentDir: string) { + const entries = readdirSync(currentDir); + + for (const entry of entries) { + const fullPath = join(currentDir, entry); + const stat = statSync(fullPath); + + if (stat.isDirectory()) { + traverse(fullPath); + } else if (entry.endsWith('.bru') && entry !== 'collection.bru') { + // collection.bru는 메타데이터 파일이므로 제외 + files.push(fullPath); + } + } + } + + traverse(dir); + return files; +} + +/** + * 파일 경로에서 도메인 추출 + * - "Solid Connection" 최상단 폴더를 제거하고 대괄호 패턴이 있는 첫 번째 폴더를 도메인으로 인식 + * - "숫자) 한글명 [영문키]" 형식: 1) 어드민 [Admin] → Admin + * - "한글명 [영문키]" 형식: 사용자 [users] → users + */ +function extractDomain(filePath: string, brunoDir: string): string { + const relativePath = relative(brunoDir, filePath); + const parts = relativePath.split('/'); + + // "Solid Connection" 폴더 제거 + const filteredParts = parts.filter(part => part !== 'Solid Connection'); + + // 대괄호 패턴이 있는 첫 번째 폴더 찾기 + const bracketPattern = /\[([^\]]+)\]/; + for (const part of filteredParts) { + const bracketMatch = part.match(bracketPattern); + if (bracketMatch) { + return bracketMatch[1].trim(); // 대괄호 안의 영문키 + } + } + + // 패턴이 없으면 파일이 있는 폴더명 사용 (마지막에서 두 번째) + return filteredParts[filteredParts.length - 2] || filteredParts[0] || 'default'; +} + +/** + * API 팩토리 및 타입 정의 생성 + */ +export async function generateHooks(options: GenerateHooksOptions): Promise { + const { brunoDir, outputDir, axiosInstancePath = '@/utils/axiosInstance', mswOutputDir, force = false } = options; + + const hashCache = new BrunoHashCache(outputDir); + hashCache.load(); + + console.log('🔍 Searching for .bru files...'); + const brunoFiles = findBrunoFiles(brunoDir); + console.log(`✅ Found ${brunoFiles.length} .bru files`); + + if (brunoFiles.length === 0) { + console.log('⚠️ No .bru files found'); + return; + } + + // 변경된 파일 필터링 + let changedFiles: string[] = []; + const skippedFiles: string[] = []; + + if (force) { + console.log('🔨 Force mode: regenerating all hooks'); + changedFiles = brunoFiles; + } else { + for (const filePath of brunoFiles) { + if (hashCache.hasChanged(filePath)) { + changedFiles.push(filePath); + } else { + skippedFiles.push(filePath); + } + } + } + + console.log(`📊 Changed: ${changedFiles.length}, Skipped: ${skippedFiles.length}`); + + if (changedFiles.length === 0) { + console.log('✅ All API clients are up to date!'); + return; + } + + const parsedChangedFiles = changedFiles.map(filePath => { + try { + const parsed = parseBrunoFile(filePath); + const domain = extractDomain(filePath, brunoDir); + return { filePath, parsed, domain }; + } catch (error) { + console.error(`❌ Error parsing ${filePath}:`, error); + return null; + } + }).filter(Boolean) as Array<{ filePath: string; parsed: any; domain: string }>; + + const allParsedFiles = brunoFiles.map(filePath => { + try { + const parsed = parseBrunoFile(filePath); + const domain = extractDomain(filePath, brunoDir); + return { filePath, parsed, domain }; + } catch (error) { + return null; + } + }).filter(Boolean) as Array<{ filePath: string; parsed: any; domain: string }>; + + console.log(`📝 Parsed ${parsedChangedFiles.length} changed files successfully`); + + mkdirSync(outputDir, { recursive: true }); + + const affectedDomains = new Set(parsedChangedFiles.map(f => f.domain)); + + const domainApiFunctions = new Map>(); + const domainDirs = new Set(); + + for (const { filePath, parsed, domain } of allParsedFiles) { + const apiFunc = extractApiFunction(parsed, filePath); + if (!apiFunc) { + continue; + } + + const domainDir = join(outputDir, domain); + if (!domainDirs.has(domainDir)) { + mkdirSync(domainDir, { recursive: true }); + domainDirs.add(domainDir); + } + + if (!domainApiFunctions.has(domain)) { + domainApiFunctions.set(domain, []); + } + domainApiFunctions.get(domain)!.push({ apiFunc, parsed }); + } + + console.log('\n🏭 Generating API factories...'); + for (const domain of affectedDomains) { + const domainDir = join(outputDir, domain); + mkdirSync(domainDir, { recursive: true }); + const apiFunctions = domainApiFunctions.get(domain) || []; + const factoryContent = generateApiFactory(apiFunctions, domain, axiosInstancePath); + const factoryPath = join(domainDir, 'api.ts'); + writeFileSync(factoryPath, factoryContent, 'utf-8'); + console.log(`✅ Generated: ${factoryPath}`); + } + + console.log('\n📋 Generating API definitions...'); + for (const domain of affectedDomains) { + const domainDir = join(outputDir, domain); + const apiFunctions = domainApiFunctions.get(domain) || []; + const definitionsContent = generateApiDefinitionsFile(apiFunctions, domain); + const definitionsPath = join(domainDir, 'apiDefinitions.ts'); + writeFileSync(definitionsPath, definitionsContent, 'utf-8'); + console.log(`✅ Generated: ${definitionsPath}`); + } + + for (const { filePath } of parsedChangedFiles) { + const currentHash = hashCache.calculateHash(filePath); + const apiFunc = extractApiFunction(parseBrunoFile(filePath), filePath); + + if (!apiFunc) { + hashCache.setHash(filePath, currentHash, []); + continue; + } + + const domain = extractDomain(filePath, brunoDir); + const domainDir = join(outputDir, domain); + const outputFiles = [ + join(domainDir, 'api.ts'), + join(domainDir, 'apiDefinitions.ts'), + ]; + + hashCache.setHash(filePath, currentHash, outputFiles); + } + + console.log('\n📄 Generating index files...'); + for (const domain of affectedDomains) { + const domainDir = join(outputDir, domain); + const files = readdirSync(domainDir).filter(f => f.endsWith('.ts') && f !== 'index.ts'); + + const indexContent = files + .map(file => { + const name = file.replace('.ts', ''); + if (name === 'api') { + const factoryName = `${toCamelCase(domain)}Api`; + return `export { ${factoryName} } from './api';`; + } + if (name === 'apiDefinitions') { + const camelDomain = toCamelCase(domain); + const definitionsValueName = `${camelDomain}ApiDefinitions`; + const definitionsTypeName = `${camelDomain.charAt(0).toUpperCase()}${camelDomain.slice(1)}ApiDefinitions`; + return `export { ${definitionsValueName}, ${definitionsTypeName} } from './apiDefinitions';`; + } + return `export * from './${name}';`; + }) + .join('\n') + '\n'; + + const indexPath = join(domainDir, 'index.ts'); + writeFileSync(indexPath, indexContent, 'utf-8'); + console.log(`✅ Generated: ${indexPath}`); + } + + hashCache.cleanup(); + hashCache.save(); + console.log(`\n💾 Hash cache saved: ${hashCache.getCachePath()}`); + + console.log('\n✨ All API clients generated successfully!'); + console.log(`\n📂 Output directory: ${outputDir}`); + console.log('\n📚 Usage example:'); + console.log(`import { applicationsApi } from './${relative(process.cwd(), join(outputDir, 'applications'))}';\n`); + console.log(`const data = await applicationsApi.getCompetitors({ params: { page: 1 } });`); + + if (mswOutputDir) { + console.log('\n🎭 Generating MSW handlers...'); + await generateMSWHandlers(parsedChangedFiles, mswOutputDir); + } +} + +/** + * MSW 핸들러 생성 + */ +async function generateMSWHandlers( + parsedFiles: Array<{ filePath: string; parsed: any; domain: string }>, + mswOutputDir: string +): Promise { + // MSW 출력 디렉토리 생성 + mkdirSync(mswOutputDir, { recursive: true }); + + // 도메인별로 핸들러 그룹화 + const domainHandlers = new Map>(); + + for (const { filePath, parsed, domain } of parsedFiles) { + const handler = generateMSWHandler(parsed, filePath, domain); + + // MSW 핸들러는 항상 생성 (docs 없어도 기본 응답 사용) + if (!handler) { + continue; + } + + if (!domainHandlers.has(domain)) { + domainHandlers.set(domain, []); + } + + domainHandlers.get(domain)!.push({ + fileName: handler.fileName, + content: handler.content, + }); + } + + // 도메인별 디렉토리 및 파일 생성 + const domains: string[] = []; + + for (const [domain, handlers] of domainHandlers.entries()) { + domains.push(domain); + + // 도메인 디렉토리 생성 + const domainDir = join(mswOutputDir, domain); + mkdirSync(domainDir, { recursive: true }); + + // 각 핸들러 파일 작성 + const handlerInfos: Array<{ fileName: string; handlerName: string }> = []; + + for (const handler of handlers) { + const handlerPath = join(domainDir, handler.fileName); + writeFileSync(handlerPath, handler.content, 'utf-8'); + console.log(`✅ MSW Generated: ${handlerPath}`); + + handlerInfos.push({ + fileName: handler.fileName, + handlerName: handler.fileName.replace('.ts', ''), + }); + } + + // 도메인별 index 파일 생성 + const domainIndexContent = generateDomainHandlersIndex(domain, handlerInfos); + const domainIndexPath = join(domainDir, 'index.ts'); + writeFileSync(domainIndexPath, domainIndexContent, 'utf-8'); + console.log(`✅ MSW Index Generated: ${domainIndexPath}`); + } + + // 전체 handlers index 파일 생성 + if (domains.length > 0) { + const mswIndexContent = generateMSWIndex(domains); + const mswIndexPath = join(mswOutputDir, 'handlers.ts'); + writeFileSync(mswIndexPath, mswIndexContent, 'utf-8'); + console.log(`✅ MSW Main Index Generated: ${mswIndexPath}`); + + console.log(`\n🎭 MSW handlers generated successfully!`); + console.log(`📂 MSW Output directory: ${mswOutputDir}`); + console.log(`\n📚 Usage example:`); + console.log(`import { handlers } from './${relative(process.cwd(), mswIndexPath).replace('.ts', '')}';\n`); + console.log(`const worker = setupWorker(...handlers);`); + } else { + console.log(`ℹ️ No MSW handlers generated`); + } +} diff --git a/packages/bruno-api-typescript/src/generator/mswGenerator.ts b/packages/bruno-api-typescript/src/generator/mswGenerator.ts new file mode 100644 index 00000000..426ec495 --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/mswGenerator.ts @@ -0,0 +1,181 @@ +/** + * MSW (Mock Service Worker) 핸들러 생성 + * Bruno 파일에서 MSW 핸들러를 자동 생성 + */ + +import { ParsedBrunoFile, extractJsonFromDocs } from '../parser/bruParser'; + +export interface MSWHandler { + domain: string; + fileName: string; + content: string; +} + +/** + * MSW 핸들러 생성 + * 모든 API에 대해 MSW 핸들러 생성 (프론트엔드에서 플래그로 제어) + * docs가 없어도 기본 응답으로 생성 (테스트 용) + */ +export function generateMSWHandler( + parsed: ParsedBrunoFile, + filePath: string, + domain: string +): MSWHandler | null { + const { method, url } = parsed.http; + + // docs 블록에서 JSON 추출 + let responseJson: any = null; + + if (parsed.docs) { + responseJson = extractJsonFromDocs(parsed.docs); + } + + // docs가 없거나 유효하지 않으면 기본 응답 사용 + if (!responseJson) { + // 기본 응답 생성 (테스트 용) + if (method === 'GET') { + responseJson = { message: 'Mock response', data: null }; + } else if (['POST', 'PUT', 'PATCH'].includes(method)) { + responseJson = { message: 'Success', id: 1 }; + } else if (method === 'DELETE') { + responseJson = { message: 'Deleted successfully' }; + } else { + responseJson = { message: 'Mock response' }; + } + } + + const handlerName = generateHandlerName(method, url); + + // MSW 핸들러 코드 생성 + const content = generateHandlerCode(method, url, responseJson); + + return { + domain, + fileName: `${handlerName}.ts`, + content, + }; +} + +/** + * 핸들러 파일명 생성 + */ +function generateHandlerName(method: string, url: string): string { + // URL에서 경로 추출 및 클린업 + const cleanUrl = url + .split('?')[0] // 쿼리 파라미터 제거 + .replace(/^\//, '') // 시작 슬래시 제거 + .replace(/\//g, '-') // 슬래시를 하이픈으로 + .replace(/:/g, '') // 콜론 제거 (path param) + .replace(/\{|\}/g, ''); // 중괄호 제거 + + return `${method.toLowerCase()}-${cleanUrl}`; +} + +/** + * MSW 핸들러 코드 생성 + */ +function generateHandlerCode(method: string, url: string, responseData: any): string { + const httpMethod = method.toLowerCase(); + const normalizedUrl = normalizeUrl(url); + const responseJsonStr = JSON.stringify(responseData, null, 2) + .split('\n') + .map((line, index) => (index === 0 ? line : ` ${line}`)) + .join('\n'); + + return `import { http, HttpResponse } from 'msw'; + +/** + * ${method.toUpperCase()} ${url} + * Auto-generated MSW handler + */ +export const handler = http.${httpMethod}('${normalizedUrl}', () => { + return HttpResponse.json( + ${responseJsonStr} + ); +}); +`; +} + +/** + * URL 정규화 + * :param -> {param} 형식으로 변환 (MSW에서 사용) + */ +function normalizeUrl(url: string): string { + // :param을 :param 형식으로 유지 (MSW는 :param 형식 지원) + return url; +} + +/** + * 도메인별 핸들러 통합 파일 생성 + */ +export function generateDomainHandlersIndex( + domain: string, + handlers: { fileName: string; handlerName: string }[] +): string { + const imports = handlers + .map((h, index) => { + const varName = `handler${index + 1}`; + const importPath = `./${h.fileName.replace('.ts', '')}`; + return `import { handler as ${varName} } from '${importPath}';`; + }) + .join('\n'); + + const exportArray = handlers + .map((_, index) => ` handler${index + 1}`) + .join(',\n'); + + return `${imports} + +/** + * ${domain} domain MSW handlers + * Auto-generated from Bruno files + */ +export const ${domain}Handlers = [ +${exportArray} +]; +`; +} + +/** + * 전체 핸들러 통합 파일 생성 + */ +export function generateMSWIndex(domains: string[]): string { + const imports = domains + .map(domain => `import { ${domain}Handlers } from './${domain}';`) + .join('\n'); + + const exportArray = domains + .map(domain => ` ...${domain}Handlers`) + .join(',\n'); + + return `${imports} + +/** + * All MSW handlers + * Auto-generated from Bruno files + * + * 프론트엔드에서 플래그로 활성/비활성 제어: + * + * 예시 1: 환경 변수로 제어 + * const ENABLE_MSW = process.env.NEXT_PUBLIC_ENABLE_MSW === 'true'; + * export const handlers = ENABLE_MSW ? [ + * ${exportArray} + * ] : []; + * + * 예시 2: 특정 도메인만 활성화 + * export const handlers = [ + * ...authHandlers, // Auth 도메인만 활성화 + * // ...usersHandlers, // Users 도메인 비활성화 + * ]; + * + * 예시 3: 조건부 필터링 + * const enabledDomains = ['Auth', 'Users']; // 활성화할 도메인 목록 + * export const handlers = [ + * ${domains.map(d => `...(enabledDomains.includes('${d}') ? ${d}Handlers : [])`).join(',\n ')} + * ]; + */ +export const handlers = [ +${exportArray} +]; +`; +} diff --git a/packages/bruno-api-typescript/src/generator/typeGenerator.ts b/packages/bruno-api-typescript/src/generator/typeGenerator.ts new file mode 100644 index 00000000..70badd2a --- /dev/null +++ b/packages/bruno-api-typescript/src/generator/typeGenerator.ts @@ -0,0 +1,337 @@ +/** + * TypeScript 타입 생성기 + * Bruno docs 블록의 JSON에서 TypeScript 타입 생성 + */ + +export interface TypeDefinition { + name: string; + content: string; +} + +/** + * JSON 값으로부터 TypeScript 타입 추론 + */ +export function inferTypeScriptType(value: any, typeName: string = 'Unknown', indent: number = 0): string { + if (value === null || value === undefined) { + return 'null'; + } + + if (Array.isArray(value)) { + if (value.length === 0) { + return 'any[]'; + } + const itemType = inferTypeScriptType(value[0], `${typeName}Item`, indent); + // 배열 아이템이 객체면 별도 인터페이스로 추출 + if (typeof value[0] === 'object' && !Array.isArray(value[0])) { + return `${typeName}Item[]`; + } + return `${itemType}[]`; + } + + const valueType = typeof value; + + switch (valueType) { + case 'string': + return 'string'; + case 'number': + return 'number'; + case 'boolean': + return 'boolean'; + case 'object': + return generateInterfaceContent(value, indent); + default: + return 'any'; + } +} + +/** + * 객체로부터 인터페이스 내용 생성 + */ +function generateInterfaceContent(obj: Record, indent: number = 0): string { + const indentStr = ' '.repeat(indent); + const properties: string[] = []; + + for (const [key, value] of Object.entries(obj)) { + const type = inferTypeScriptType(value, toPascalCase(key), indent + 1); + properties.push(`${indentStr} ${key}: ${type};`); + } + + return `{\n${properties.join('\n')}\n${indentStr}}`; +} + +/** + * JSON 객체로부터 TypeScript 인터페이스 생성 + */ +export function generateTypeScriptInterface( + json: any, + interfaceName: string +): TypeDefinition[] { + const definitions: TypeDefinition[] = []; + + // 중첩된 타입 추출 (메인 타입 제외) + extractNestedTypes(json, '', definitions, interfaceName, true); + + // 메인 인터페이스 생성 + const properties: string[] = []; + for (const [key, value] of Object.entries(json)) { + let type = getPropertyType(value, toPascalCase(key), interfaceName); + + // 배열인 경우 유니온 타입 확인 + if (Array.isArray(value) && value.length > 0) { + const types = new Set(); + for (const item of value) { + if (item === null || item === undefined) { + types.add('null'); + } else { + const itemType = getPropertyType(item, toPascalCase(key), `${interfaceName}${toPascalCase(key)}Item`); + types.add(itemType); + } + } + const typeArray = Array.from(types); + if (typeArray.length > 1) { + type = `(${typeArray.join(' | ')})[]`; + } + } else if (value === null || value === undefined) { + // 단일 null 값은 그대로 유지 (유니온 타입 생성 불가) + type = 'null'; + } + + properties.push(` ${key}: ${type};`); + } + + // 빈 인터페이스인 경우 Record 타입으로 생성 + if (properties.length === 0) { + const emptyType = `export type ${interfaceName} = Record;`; + definitions.push({ name: interfaceName, content: emptyType }); + } else { + const mainInterface = `export interface ${interfaceName} {\n${properties.join('\n')}\n}`; + definitions.push({ name: interfaceName, content: mainInterface }); + } + + return definitions; +} + +/** + * 중첩된 타입 추출 + */ +function extractNestedTypes( + value: any, + typeName: string, + definitions: TypeDefinition[], + parentTypeName?: string, + isRoot: boolean = false +): void { + if (Array.isArray(value) && value.length > 0) { + const itemType = value[0]; + if (typeof itemType === 'object' && !Array.isArray(itemType) && itemType !== null) { + // 부모 타입 이름을 포함하여 고유한 타입 이름 생성 + const itemTypeName = parentTypeName + ? `${parentTypeName}${typeName}Item` + : `${typeName}Item`; + const properties: string[] = []; + + // 배열의 모든 아이템을 확인하여 각 필드의 타입 수집 + const fieldTypes = new Map>(); + + // 모든 아이템을 순회하며 각 필드의 타입 수집 + for (const item of value) { + if (typeof item === 'object' && !Array.isArray(item) && item !== null) { + for (const [key, val] of Object.entries(item)) { + if (!fieldTypes.has(key)) { + fieldTypes.set(key, new Set()); + } + const typeSet = fieldTypes.get(key)!; + + if (val === null || val === undefined) { + typeSet.add('null'); + } else { + // 중첩된 객체인 경우 부모 타입 이름 포함 (중복 방지) + const propTypeName = typeof val === 'object' && !Array.isArray(val) && val !== null + ? `${itemTypeName}${toPascalCase(key)}` + : toPascalCase(key); + const propType = getPropertyType(val, toPascalCase(key), itemTypeName); + typeSet.add(propType); + } + } + } + } + + // 유니온 타입 생성 및 중첩 타입 추출 + for (const [key, typeSet] of fieldTypes) { + const types = Array.from(typeSet); + const propType = types.length === 1 + ? types[0] + : types.join(' | '); + properties.push(` ${key}: ${propType};`); + + // 재귀적으로 중첩된 타입 추출 + const val = itemType[key]; + if (val !== null && val !== undefined) { + const nestedTypeName = `${itemTypeName}${toPascalCase(key)}`; + extractNestedTypes(val, toPascalCase(key), definitions, itemTypeName); + } + } + + const interfaceContent = `export interface ${itemTypeName} {\n${properties.join('\n')}\n}`; + definitions.unshift({ name: itemTypeName, content: interfaceContent }); + } + } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + // 루트 레벨이 아니고 부모 타입 이름이 있는 경우에만 타입 정의 생성 + if (!isRoot && parentTypeName && typeName) { + const nestedTypeName = `${parentTypeName}${typeName}`; + const properties: string[] = []; + const fieldTypes = new Map>(); + + // 모든 필드의 타입 수집 + for (const [key, val] of Object.entries(value)) { + if (!fieldTypes.has(key)) { + fieldTypes.set(key, new Set()); + } + const typeSet = fieldTypes.get(key)!; + + if (val === null || val === undefined) { + typeSet.add('null'); + } else { + const propType = getPropertyType(val, toPascalCase(key), nestedTypeName); + typeSet.add(propType); + } + } + + // 유니온 타입 생성 + for (const [key, typeSet] of fieldTypes) { + const types = Array.from(typeSet); + const propType = types.length === 1 + ? types[0] + : types.join(' | '); + properties.push(` ${key}: ${propType};`); + + // 재귀적으로 중첩된 타입 추출 + const val = value[key]; + if (val !== null && val !== undefined) { + extractNestedTypes(val, toPascalCase(key), definitions, nestedTypeName, false); + } + } + + // 타입 정의 추가 + if (properties.length > 0) { + const interfaceContent = `export interface ${nestedTypeName} {\n${properties.join('\n')}\n}`; + definitions.unshift({ name: nestedTypeName, content: interfaceContent }); + } + } else { + // 루트 레벨이거나 타입 이름이 없는 경우, 자식만 재귀적으로 추출 + for (const [key, val] of Object.entries(value)) { + const childParentTypeName = isRoot ? parentTypeName : (parentTypeName ? `${parentTypeName}${typeName}` : typeName); + extractNestedTypes(val, toPascalCase(key), definitions, childParentTypeName, false); + } + } + } +} + +/** + * 프로퍼티 타입 결정 + */ +function getPropertyType(value: any, typeName: string, parentTypeName?: string): string { + if (value === null || value === undefined) { + return 'null'; + } + + if (Array.isArray(value)) { + if (value.length === 0) { + return 'any[]'; + } + const itemType = value[0]; + if (typeof itemType === 'object' && !Array.isArray(itemType) && itemType !== null) { + // 부모 타입 이름을 포함하여 고유한 타입 이름 생성 + const itemTypeName = parentTypeName + ? `${parentTypeName}${typeName}Item` + : `${typeName}Item`; + return `${itemTypeName}[]`; + } + // 배열의 모든 아이템을 확인하여 유니온 타입 생성 + const types = new Set(); + for (const item of value) { + if (item === null || item === undefined) { + types.add('null'); + } else { + types.add(getPropertyType(item, typeName, parentTypeName)); + } + } + const typeArray = Array.from(types); + if (typeArray.length === 1) { + return `${typeArray[0]}[]`; + } + return `(${typeArray.join(' | ')})[]`; + } + + const valueType = typeof value; + + switch (valueType) { + case 'string': + return 'string'; + case 'number': + return 'number'; + case 'boolean': + return 'boolean'; + case 'object': + // 부모 타입 이름을 포함하여 고유한 타입 이름 생성 (중복 방지) + if (parentTypeName) { + // 이미 부모 타입 이름이 포함되어 있는지 확인 + if (typeName.startsWith(parentTypeName)) { + return typeName; + } + return `${parentTypeName}${typeName}`; + } + return typeName; + default: + return 'any'; + } +} + +/** + * 문자열을 PascalCase로 변환 + */ +function toPascalCase(str: string): string { + return str + .replace(/[-_](.)/g, (_, c) => c.toUpperCase()) + .replace(/^(.)/, (_, c) => c.toUpperCase()); +} + +/** + * 문자열을 camelCase로 변환 + */ +export function toCamelCase(str: string): string { + return str + .replace(/[-_](.)/g, (_, c) => c.toUpperCase()) + .replace(/^(.)/, (_, c) => c.toLowerCase()); +} + +/** + * URL 경로를 함수명으로 변환 + * 예: /applications/competitors -> getApplicationsCompetitors + */ +export function urlToFunctionName(method: string, url: string): string { + // 경로 파라미터 제거 및 처리 + const pathParts = url + .split('/') + .filter(part => part.length > 0) + .map(part => { + // :id, {id} 같은 파라미터 처리 + if (part.startsWith(':') || part.startsWith('{')) { + return 'ById'; + } + return toPascalCase(part); + }); + + const baseName = pathParts.join(''); + const methodPrefix = method.toLowerCase(); + + return `${methodPrefix}${baseName}`; +} + +/** + * 함수명을 타입명으로 변환 + * 예: getApplicationsCompetitors -> GetApplicationsCompetitorsResponse + */ +export function functionNameToTypeName(functionName: string, suffix: string = 'Response'): string { + return `${toPascalCase(functionName)}${suffix}`; +} diff --git a/packages/bruno-api-typescript/src/index.ts b/packages/bruno-api-typescript/src/index.ts new file mode 100644 index 00000000..8a6130e7 --- /dev/null +++ b/packages/bruno-api-typescript/src/index.ts @@ -0,0 +1,25 @@ +/** + * bruno-openapi-sync + * Main entry point for programmatic usage + */ + +export { parseBrunoFile, extractJsonFromDocs } from './parser/bruParser'; +export type { ParsedBrunoFile, BrunoRequest } from './parser/bruParser'; + +export { inferSchema } from './converter/schemaBuilder'; +export type { OpenAPISchema } from './converter/schemaBuilder'; + +export { convertBrunoToOpenAPI } from './converter/openapiConverter'; +export type { OpenAPISpec, ConversionOptions } from './converter/openapiConverter'; + +export { detectChanges, groupChangesByDomain, isBreakingChange } from './diff/changeDetector'; +export type { + ChangeReport, + EndpointChange, + FieldChange, + ChangeType, + ChangeSeverity, +} from './diff/changeDetector'; + +export { generateChangelog, formatConsoleOutput } from './diff/changelogGenerator'; +export type { ChangelogOptions, ChangelogFormat } from './diff/changelogGenerator'; diff --git a/packages/bruno-api-typescript/src/parser/bruParser.ts b/packages/bruno-api-typescript/src/parser/bruParser.ts new file mode 100644 index 00000000..316d2c52 --- /dev/null +++ b/packages/bruno-api-typescript/src/parser/bruParser.ts @@ -0,0 +1,297 @@ +/** + * Bruno .bru 파일 파서 + * .bru 파일을 읽어서 구조화된 데이터로 변환 + */ + +import { readFileSync } from 'fs'; +import { resolve } from 'path'; + +export interface BrunoRequest { + method: string; + url: string; + name: string; + docs?: string; + headers?: Record; + body?: string; + auth?: { + type: string; + [key: string]: any; + }; +} + +export interface ParsedBrunoFile { + meta: { + name: string; + type: string; + seq?: number; + done?: boolean; + }; + http: { + method: string; + url: string; + }; + headers?: Record; + auth?: { + type: string; + [key: string]: any; + }; + body?: { + type: string; + content: string; + }; + docs?: string; + script?: { + pre?: string; + post?: string; + }; + tests?: string; +} + +/** + * .bru 파일 파싱 + */ +export function parseBrunoFile(filePath: string): ParsedBrunoFile { + const content = readFileSync(filePath, 'utf-8'); + const lines = content.split('\n'); + + const result: ParsedBrunoFile = { + meta: { + name: '', + type: 'http', + }, + http: { + method: 'GET', + url: '', + }, + }; + + let currentBlock: string | null = null; + let blockContent: string[] = []; + let inCodeBlock = false; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const trimmed = line.trim(); + + // 블록 시작 감지 + if (trimmed === 'meta {') { + currentBlock = 'meta'; + blockContent = []; + continue; + } else if (trimmed.match(/^(get|post|put|patch|delete|head|options)\s*\{/i)) { + // HTTP 메서드 블록 형식: put { url: ... } + const match = trimmed.match(/^(get|post|put|patch|delete|head|options)\s*\{/i); + if (match) { + result.http.method = match[1].toUpperCase(); + currentBlock = 'http'; + blockContent = []; + continue; + } + } else if (trimmed.match(/^(get|post|put|patch|delete|head|options)\s+/i)) { + // HTTP 메서드 라인 형식: get /api/endpoint + const match = trimmed.match(/^(get|post|put|patch|delete|head|options)\s+(.+)$/i); + if (match) { + result.http.method = match[1].toUpperCase(); + result.http.url = match[2].trim(); + } + continue; + } else if (trimmed === 'headers {') { + currentBlock = 'headers'; + blockContent = []; + continue; + } else if (trimmed === 'body:json {') { + currentBlock = 'body'; + blockContent = []; + continue; + } else if (trimmed === 'docs {') { + currentBlock = 'docs'; + blockContent = []; + inCodeBlock = false; + continue; + } else if (trimmed === 'script:pre-request {') { + currentBlock = 'script:pre'; + blockContent = []; + continue; + } else if (trimmed === 'script:post-response {') { + currentBlock = 'script:post'; + blockContent = []; + continue; + } else if (trimmed === 'tests {') { + currentBlock = 'tests'; + blockContent = []; + continue; + } + + // 블록 종료 감지 + if (trimmed === '}' && currentBlock && !inCodeBlock) { + // 블록 파싱 + parseBlock(result, currentBlock, blockContent); + currentBlock = null; + blockContent = []; + continue; + } + + // 블록 내용 수집 + if (currentBlock) { + // docs 블록에서 코드 블록 처리 + if (currentBlock === 'docs') { + if (trimmed === '```json' || trimmed === '```') { + inCodeBlock = !inCodeBlock; + // 코드 블록 라인도 포함 (정규식 매칭을 위해) + blockContent.push(line); + continue; + } + } + blockContent.push(line); + } + } + + return result; +} + +/** + * 블록 파싱 + */ +function parseBlock(result: ParsedBrunoFile, blockName: string, content: string[]): void { + switch (blockName) { + case 'meta': + parseMeta(result, content); + break; + case 'http': + parseHttp(result, content); + break; + case 'headers': + parseHeaders(result, content); + break; + case 'body': + parseBody(result, content); + break; + case 'docs': + parseDocs(result, content); + break; + case 'script:pre': + if (!result.script) result.script = {}; + result.script.pre = content.join('\n').trim(); + break; + case 'script:post': + if (!result.script) result.script = {}; + result.script.post = content.join('\n').trim(); + break; + case 'tests': + result.tests = content.join('\n').trim(); + break; + } +} + +/** + * HTTP 블록 파싱 (put { url: ... } 형식) + */ +function parseHttp(result: ParsedBrunoFile, lines: string[]): void { + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed.startsWith('url:')) { + result.http.url = trimmed.substring(4).trim(); + } + } +} + +/** + * meta 블록 파싱 + */ +function parseMeta(result: ParsedBrunoFile, lines: string[]): void { + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed.startsWith('name:')) { + result.meta.name = trimmed.substring(5).trim(); + } else if (trimmed.startsWith('type:')) { + result.meta.type = trimmed.substring(5).trim(); + } else if (trimmed.startsWith('seq:')) { + result.meta.seq = parseInt(trimmed.substring(4).trim(), 10); + } else if (trimmed.startsWith('done:')) { + const value = trimmed.substring(5).trim().toLowerCase(); + result.meta.done = value === 'true'; + } + } +} + +/** + * headers 블록 파싱 + */ +function parseHeaders(result: ParsedBrunoFile, lines: string[]): void { + result.headers = {}; + for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed) continue; + const colonIndex = trimmed.indexOf(':'); + if (colonIndex > 0) { + const key = trimmed.substring(0, colonIndex).trim(); + const value = trimmed.substring(colonIndex + 1).trim(); + result.headers[key] = value; + } + } +} + +/** + * body 블록 파싱 + */ +function parseBody(result: ParsedBrunoFile, lines: string[]): void { + const content = lines.join('\n').trim(); + result.body = { + type: 'json', + content, + }; +} + +/** + * docs 블록 파싱 (JSON 추출) + */ +function parseDocs(result: ParsedBrunoFile, lines: string[]): void { + const content = lines.join('\n').trim(); + result.docs = content; +} + +/** + * docs 블록에서 JSON 추출 + * 상태 코드별 응답 지원: ## 200 OK 형식 + */ +export function extractJsonFromDocs(docs: string): any { + try { + // ## 200 OK 형식의 상태 코드별 응답 지원 + // 패턴: ## 200 OK (또는 ## 200) 다음에 빈 줄과 코드 블록 + const statusCodePattern = /##\s*(\d+)\s+[^\n]*(?:\n|$)(?:[^\n]*\n)*?\s*```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/g; + let match; + let json200 = null; + + // 모든 상태 코드 응답 찾기 + while ((match = statusCodePattern.exec(docs)) !== null) { + const statusCode = parseInt(match[1]); + const jsonContent = match[2].trim(); + + // 200 OK만 사용 + if (statusCode === 200) { + try { + json200 = JSON.parse(jsonContent); + break; // 200 OK를 찾으면 중단 + } catch (e) { + // JSON 파싱 실패시 무시 + } + } + } + + // 200 OK를 찾지 못한 경우 기존 로직 사용 + if (json200) { + return json200; + } + + // 기존 로직: 단일 JSON 코드 블록 + const jsonMatch = docs.match(/```json\s*([\s\S]*?)\s*```/); + if (jsonMatch && jsonMatch[1]) { + return JSON.parse(jsonMatch[1].trim()); + } + + // 일반 JSON 파싱 시도 + return JSON.parse(docs.trim()); + } catch (error) { + return null; + } +} diff --git a/packages/bruno-api-typescript/tests/cli.test.js b/packages/bruno-api-typescript/tests/cli.test.js new file mode 100644 index 00000000..bc778738 --- /dev/null +++ b/packages/bruno-api-typescript/tests/cli.test.js @@ -0,0 +1,561 @@ +/** + * CLI 기능 테스트 + * Node.js 기본 test runner 사용 + */ + +const { test, describe, before, after } = require('node:test'); +const assert = require('node:assert'); +const { existsSync, rmSync, mkdirSync, readFileSync } = require('fs'); +const { execSync } = require('child_process'); +const { join } = require('path'); + +const FIXTURES_DIR = join(__dirname, 'fixtures'); +const TEST_OUTPUT_DIR = join(__dirname, 'output'); + +// 테스트 전 정리 +before(() => { + if (existsSync(TEST_OUTPUT_DIR)) { + rmSync(TEST_OUTPUT_DIR, { recursive: true, force: true }); + } + mkdirSync(TEST_OUTPUT_DIR, { recursive: true }); +}); + +// 테스트 후 정리 +after(() => { + if (existsSync(TEST_OUTPUT_DIR)) { + rmSync(TEST_OUTPUT_DIR, { recursive: true, force: true }); + } +}); + +describe('OpenAPI 생성 테스트', () => { + test('기본 OpenAPI 스펙 생성', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputFile = join(TEST_OUTPUT_DIR, 'openapi.json'); + + // CLI 실행 + execSync(`node dist/cli/index.js generate -i ${inputDir} -o ${outputFile}`, { + cwd: join(__dirname, '..'), + }); + + // 파일 생성 확인 + assert.ok(existsSync(outputFile), 'OpenAPI 파일이 생성되어야 함'); + + // JSON 파싱 가능 확인 + const spec = JSON.parse(readFileSync(outputFile, 'utf-8')); + + // 기본 구조 검증 + assert.ok(spec.openapi, 'openapi 버전이 있어야 함'); + assert.ok(spec.info, 'info 객체가 있어야 함'); + assert.ok(spec.paths, 'paths 객체가 있어야 함'); + + // 엔드포인트 확인 + assert.ok(spec.paths['/users/profile'], '/users/profile 엔드포인트가 있어야 함'); + assert.ok(spec.paths['/applications/competitors'], '/applications/competitors 엔드포인트가 있어야 함'); + + // GET 메서드 확인 + assert.ok(spec.paths['/users/profile'].get, 'GET /users/profile가 있어야 함'); + assert.ok(spec.paths['/applications/competitors'].get, 'GET /applications/competitors가 있어야 함'); + + console.log('✅ OpenAPI 생성 테스트 통과'); + }); + + test('도메인별 태그 그룹화', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputFile = join(TEST_OUTPUT_DIR, 'openapi-tags.json'); + + execSync(`node dist/cli/index.js generate -i ${inputDir} -o ${outputFile}`, { + cwd: join(__dirname, '..'), + }); + + const spec = JSON.parse(readFileSync(outputFile, 'utf-8')); + + // 태그 확인 + assert.ok(spec.paths['/users/profile'].get.tags, '태그가 있어야 함'); + assert.ok(spec.paths['/users/profile'].get.tags.includes('users'), 'users 태그가 있어야 함'); + + console.log('✅ 도메인별 태그 그룹화 테스트 통과'); + }); + + test('응답 스키마 생성', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputFile = join(TEST_OUTPUT_DIR, 'openapi-schema.json'); + + execSync(`node dist/cli/index.js generate -i ${inputDir} -o ${outputFile}`, { + cwd: join(__dirname, '..'), + }); + + const spec = JSON.parse(readFileSync(outputFile, 'utf-8')); + + // 응답 스키마 확인 + const userProfileResponse = spec.paths['/users/profile'].get.responses['200']; + assert.ok(userProfileResponse, '200 응답이 있어야 함'); + assert.ok(userProfileResponse.content, 'content가 있어야 함'); + assert.ok(userProfileResponse.content['application/json'], 'application/json이 있어야 함'); + assert.ok(userProfileResponse.content['application/json'].schema, 'schema가 있어야 함'); + + const schema = userProfileResponse.content['application/json'].schema; + assert.ok(schema.properties, 'properties가 있어야 함'); + assert.ok(schema.properties.id, 'id 필드가 있어야 함'); + assert.ok(schema.properties.username, 'username 필드가 있어야 함'); + + console.log('✅ 응답 스키마 생성 테스트 통과'); + }); +}); + +describe('API 클라이언트 생성 테스트', () => { + test('기본 API 파일 생성', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputDir = join(TEST_OUTPUT_DIR, 'apis'); + + execSync(`node dist/cli/index.js generate-hooks -i ${inputDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const usersDir = join(outputDir, 'users'); + const applicationsDir = join(outputDir, 'applications'); + assert.ok(existsSync(usersDir), 'users 디렉토리가 생성되어야 함'); + assert.ok(existsSync(applicationsDir), 'applications 디렉토리가 생성되어야 함'); + + const usersApiFile = join(usersDir, 'api.ts'); + const applicationsApiFile = join(applicationsDir, 'api.ts'); + assert.ok(existsSync(usersApiFile), 'users/api.ts 팩토리 파일이 생성되어야 함'); + assert.ok(existsSync(applicationsApiFile), 'applications/api.ts 팩토리 파일이 생성되어야 함'); + + const usersDefinitionsFile = join(usersDir, 'apiDefinitions.ts'); + const applicationsDefinitionsFile = join(applicationsDir, 'apiDefinitions.ts'); + assert.ok(existsSync(usersDefinitionsFile), 'users/apiDefinitions.ts 파일이 생성되어야 함'); + assert.ok(existsSync(applicationsDefinitionsFile), 'applications/apiDefinitions.ts 파일이 생성되어야 함'); + + console.log('✅ 기본 API 파일 생성 테스트 통과'); + }); + + test('API 정의 파일 내용 검증', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputDir = join(TEST_OUTPUT_DIR, 'apis-content'); + + execSync(`node dist/cli/index.js generate-hooks -i ${inputDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const usersDefinitionsFile = join(outputDir, 'users', 'apiDefinitions.ts'); + const content = readFileSync(usersDefinitionsFile, 'utf-8'); + + assert.ok(content.includes('import type'), 'type-only import가 있어야 함'); + assert.ok(content.includes('from \'./api\''), 'api.ts로부터 타입 import가 있어야 함'); + assert.ok(content.includes('export const usersApiDefinitions'), 'usersApiDefinitions 객체가 있어야 함'); + assert.ok(content.includes('method:'), 'method 필드가 있어야 함'); + assert.ok(content.includes('path:'), 'path 필드가 있어야 함'); + assert.ok(content.includes('response:'), 'response 필드가 있어야 함'); + + console.log('✅ API 정의 파일 내용 검증 테스트 통과'); + }); + + test('API 팩토리 파일 내용 검증', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputDir = join(TEST_OUTPUT_DIR, 'apis-factory'); + + execSync(`node dist/cli/index.js generate-hooks -i ${inputDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const usersApiFile = join(outputDir, 'users', 'api.ts'); + const content = readFileSync(usersApiFile, 'utf-8'); + + // 필수 import 확인 + assert.ok(content.includes('import { axiosInstance }'), 'axiosInstance import가 있어야 함'); + + // 팩토리 객체 확인 + assert.ok(content.includes('export const usersApi'), 'usersApi 팩토리 객체가 있어야 함'); + assert.ok(content.includes('getGetProfile:'), 'getGetProfile 함수가 있어야 함'); + + // 함수 시그니처 확인 + assert.ok(content.includes('async ('), 'async 함수가 있어야 함'); + assert.ok(content.includes('Promise<'), 'Promise 타입이 있어야 함'); + + console.log('✅ API 팩토리 파일 내용 검증 테스트 통과'); + }); + + test('index 파일 생성', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputDir = join(TEST_OUTPUT_DIR, 'apis-index'); + + execSync(`node dist/cli/index.js generate-hooks -i ${inputDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const usersIndex = join(outputDir, 'users', 'index.ts'); + const applicationsIndex = join(outputDir, 'applications', 'index.ts'); + + assert.ok(existsSync(usersIndex), 'users/index.ts가 생성되어야 함'); + assert.ok(existsSync(applicationsIndex), 'applications/index.ts가 생성되어야 함'); + + const usersIndexContent = readFileSync(usersIndex, 'utf-8'); + assert.ok(usersIndexContent.includes('export'), 'export가 있어야 함'); + assert.ok(usersIndexContent.includes('usersApi'), 'usersApi export가 있어야 함'); + assert.ok(usersIndexContent.includes('apiDefinitions'), 'apiDefinitions export가 있어야 함'); + + console.log('✅ index 파일 생성 테스트 통과'); + }); +}); + +describe('변경사항 감지 테스트', () => { + test('변경사항 감지 기능', () => { + const brunoV1 = join(FIXTURES_DIR, 'bruno'); + const brunoV2 = join(FIXTURES_DIR, 'bruno-v2'); + const outputV1 = join(TEST_OUTPUT_DIR, 'openapi-v1.json'); + const outputV2 = join(TEST_OUTPUT_DIR, 'openapi-v2.json'); + + // V1 생성 + execSync(`node dist/cli/index.js generate -i ${brunoV1} -o ${outputV1}`, { + cwd: join(__dirname, '..'), + }); + + // V2 생성 (변경사항 포함) + execSync(`node dist/cli/index.js generate -i ${brunoV2} -o ${outputV2}`, { + cwd: join(__dirname, '..'), + }); + + // 파일 비교 + const specV1 = JSON.parse(readFileSync(outputV1, 'utf-8')); + const specV2 = JSON.parse(readFileSync(outputV2, 'utf-8')); + + // V2에 추가된 엔드포인트 확인 + const v1Paths = Object.keys(specV1.paths); + const v2Paths = Object.keys(specV2.paths); + + assert.ok(v2Paths.length >= v1Paths.length, 'V2가 V1보다 많거나 같은 엔드포인트를 가져야 함'); + + console.log('✅ 변경사항 감지 기능 테스트 통과'); + }); +}); + +describe('새로운 폴더명 패턴 테스트', () => { + test('숫자) 한글명 [영문키] 패턴 추출', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputDir = join(TEST_OUTPUT_DIR, 'apis-pattern'); + + execSync(`node dist/cli/index.js generate-hooks -i ${inputDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const adminDir = join(outputDir, 'Admin'); + assert.ok(existsSync(adminDir), '7) 어드민 [Admin] 폴더에서 Admin이 생성되어야 함'); + + const apiFile = join(adminDir, 'api.ts'); + const definitionsFile = join(adminDir, 'apiDefinitions.ts'); + assert.ok(existsSync(apiFile), 'Admin/api.ts 파일이 생성되어야 함'); + assert.ok(existsSync(definitionsFile), 'Admin/apiDefinitions.ts 파일이 생성되어야 함'); + + console.log('✅ 숫자) 한글명 [영문키] 패턴 테스트 통과'); + }); + + test('한글명 [영문키] 파일명 패턴 추출', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputDir = join(TEST_OUTPUT_DIR, 'apis-filename-pattern'); + + execSync(`node dist/cli/index.js generate-hooks -i ${inputDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const adminApiFile = join(outputDir, 'Admin', 'api.ts'); + const adminApiContent = readFileSync(adminApiFile, 'utf-8'); + + assert.ok(adminApiContent.includes('getGetList'), 'getGetList 함수가 생성되어야 함'); + assert.ok(adminApiContent.includes('export const adminApi'), 'adminApi 팩토리가 생성되어야 함'); + + const definitionsFile = join(outputDir, 'Admin', 'apiDefinitions.ts'); + const definitionsContent = readFileSync(definitionsFile, 'utf-8'); + assert.ok(definitionsContent.includes('getGetList'), 'getGetList 정의가 생성되어야 함'); + + console.log('✅ 한글명 [영문키] 파일명 패턴 테스트 통과'); + }); +}); + +describe('상태 코드별 응답 파싱 테스트', () => { + test('200 OK만 추출 (404 무시)', () => { + const inputDir = join(FIXTURES_DIR, 'bruno'); + const outputFile = join(TEST_OUTPUT_DIR, 'openapi-status-codes.json'); + + execSync(`node dist/cli/index.js generate -i ${inputDir} -o ${outputFile}`, { + cwd: join(__dirname, '..'), + }); + + const spec = JSON.parse(readFileSync(outputFile, 'utf-8')); + + // /mentors 엔드포인트 확인 + const mentorsPath = spec.paths['/mentors']; + assert.ok(mentorsPath, '/mentors 엔드포인트가 있어야 함'); + + // 200 응답만 있는지 확인 (404는 무시되어야 함) + const getMethod = mentorsPath.get; + assert.ok(getMethod, 'GET 메서드가 있어야 함'); + assert.ok(getMethod.responses['200'], '200 응답이 있어야 함'); + assert.ok(!getMethod.responses['404'], '404 응답은 포함되지 않아야 함'); + + // 200 응답의 스키마 확인 + const response200 = getMethod.responses['200']; + assert.ok(response200.content, 'content가 있어야 함'); + assert.ok(response200.content['application/json'], 'application/json이 있어야 함'); + assert.ok(response200.content['application/json'].schema, 'schema가 있어야 함'); + + const schema = response200.content['application/json'].schema; + assert.ok(schema.properties, 'properties가 있어야 함'); + assert.ok(schema.properties.nextPageNumber, 'nextPageNumber 필드가 있어야 함'); + assert.ok(schema.properties.content, 'content 필드가 있어야 함'); + + console.log('✅ 상태 코드별 응답 파싱 테스트 통과'); + }); +}); + +describe('컬렉션 폴더 지원 테스트', () => { + test('Solid Connection 폴더 제거 및 도메인 추출', () => { + const collectionFixtureDir = join(TEST_OUTPUT_DIR, 'collection-fixture'); + const collectionDir = join(collectionFixtureDir, 'Solid Connection', '1) 인증 [Auth]'); + mkdirSync(collectionDir, { recursive: true }); + + const testFile = join(collectionDir, 'sign-out.bru'); + const bruContent = `meta { + name: Sign Out + type: http +} + +post /auth/sign-out +`; + require('fs').writeFileSync(testFile, bruContent); + + const outputDir = join(TEST_OUTPUT_DIR, 'collection-output'); + execSync(`node dist/cli/index.js generate-hooks -i ${collectionFixtureDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const authDir = join(outputDir, 'Auth'); + assert.ok(existsSync(authDir), 'Auth 디렉토리가 생성되어야 함 (Solid Connection 폴더 제거)'); + + const authApiFile = join(authDir, 'api.ts'); + const authApiContent = readFileSync(authApiFile, 'utf-8'); + assert.ok(authApiContent.includes('postSignOut'), 'postSignOut 함수가 생성되어야 함 (메서드 prefix 포함)'); + + const authDefinitionsFile = join(authDir, 'apiDefinitions.ts'); + assert.ok(existsSync(authDefinitionsFile), 'Auth/apiDefinitions.ts 파일이 생성되어야 함'); + + console.log('✅ Solid Connection 폴더 제거 및 도메인 추출 테스트 통과'); + }); +}); + +describe('파일명 규칙 테스트', () => { + test('메서드 prefix 없는 파일명 정상 동작 및 함수명에 메서드 prefix 포함', () => { + const noPrefixFixtureDir = join(TEST_OUTPUT_DIR, 'no-prefix-fixture'); + const usersDir = join(noPrefixFixtureDir, 'users'); + mkdirSync(usersDir, { recursive: true }); + + const accountFile = join(usersDir, 'account.bru'); + const accountContent = `meta { + name: Delete Account + type: http +} + +delete /users/account +`; + require('fs').writeFileSync(accountFile, accountContent); + + const signUpFile = join(usersDir, 'sign-up.bru'); + const signUpContent = `meta { + name: Sign Up + type: http +} + +post /users/sign-up + +body:json { + { + "email": "test@example.com", + "password": "password123" + } +} + +docs { + \`\`\`json + { + "id": 1, + "email": "test@example.com", + "createdAt": "2025-01-01T00:00:00Z" + } + \`\`\` +} +`; + require('fs').writeFileSync(signUpFile, signUpContent); + + const outputDir = join(TEST_OUTPUT_DIR, 'no-prefix-output'); + execSync(`node dist/cli/index.js generate-hooks -i ${noPrefixFixtureDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + const apiFile = join(outputDir, 'users', 'api.ts'); + const apiContent = readFileSync(apiFile, 'utf-8'); + assert.ok(apiContent.includes('deleteAccount'), 'deleteAccount 함수가 생성되어야 함 (메서드 prefix 포함)'); + assert.ok(apiContent.includes('postSignUp'), 'postSignUp 함수가 생성되어야 함 (메서드 prefix 포함)'); + + const definitionsFile = join(outputDir, 'users', 'apiDefinitions.ts'); + const definitionsContent = readFileSync(definitionsFile, 'utf-8'); + assert.ok(definitionsContent.includes('deleteAccount'), 'deleteAccount 정의가 생성되어야 함'); + assert.ok(definitionsContent.includes('postSignUp'), 'postSignUp 정의가 생성되어야 함'); + + console.log('✅ 메서드 prefix 없는 파일명 및 함수명 메서드 prefix 포함 테스트 통과'); + }); +}); + +describe('빈 타입 생성 테스트', () => { + test('빈 객체 {}인 경우 Record 타입 생성', () => { + const emptyObjectFixtureDir = join(FIXTURES_DIR, 'bruno-empty-object'); + mkdirSync(emptyObjectFixtureDir, { recursive: true }); + + // 폴더 구조 생성 + const testFolder = join(emptyObjectFixtureDir, 'test'); + mkdirSync(testFolder, { recursive: true }); + + const emptyObjectFile = join(testFolder, 'empty-response.bru'); + const emptyObjectContent = `meta { + name: Empty Response Test + type: http +} + +get /test/empty + +docs { + \`\`\`json + {} + \`\`\` +} +`; + require('fs').writeFileSync(emptyObjectFile, emptyObjectContent); + + const outputDir = join(TEST_OUTPUT_DIR, 'empty-object-output'); + execSync(`node dist/cli/index.js generate-hooks -i ${emptyObjectFixtureDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + // api.ts 파일 확인 (도메인은 폴더명 'test'가 됨) + const apiFile = join(outputDir, 'test', 'api.ts'); + assert.ok(existsSync(apiFile), 'api.ts 파일이 생성되어야 함'); + + const apiContent = readFileSync(apiFile, 'utf-8'); + assert.ok(apiContent.includes('Record'), '빈 객체는 Record 타입이어야 함'); + assert.ok(!apiContent.includes('export interface'), '빈 인터페이스는 생성되지 않아야 함'); + + console.log('✅ 빈 객체 Record 타입 생성 테스트 통과'); + }); + + test('parsed.docs가 있지만 JSON 추출 실패 시 void 타입 생성', () => { + const invalidJsonFixtureDir = join(FIXTURES_DIR, 'bruno-invalid-json'); + mkdirSync(invalidJsonFixtureDir, { recursive: true }); + + // 폴더 구조 생성 + const testFolder = join(invalidJsonFixtureDir, 'test'); + mkdirSync(testFolder, { recursive: true }); + + const invalidJsonFile = join(testFolder, 'invalid-json.bru'); + const invalidJsonContent = `meta { + name: Invalid JSON Test + type: http +} + +get /test/invalid + +docs { + 이것은 유효하지 않은 JSON입니다 + { invalid json } +} +`; + require('fs').writeFileSync(invalidJsonFile, invalidJsonContent); + + const outputDir = join(TEST_OUTPUT_DIR, 'invalid-json-output'); + execSync(`node dist/cli/index.js generate-hooks -i ${invalidJsonFixtureDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + // api.ts 파일 확인 (도메인은 폴더명 'test'가 됨) + const apiFile = join(outputDir, 'test', 'api.ts'); + assert.ok(existsSync(apiFile), 'api.ts 파일이 생성되어야 함'); + + const apiContent = readFileSync(apiFile, 'utf-8'); + assert.ok(apiContent.includes('void'), 'JSON 추출 실패 시 void 타입이 생성되어야 함'); + + console.log('✅ JSON 추출 실패 시 void 타입 생성 테스트 통과'); + }); + + test('빈 배열 []인 경우 any[] 타입 생성', () => { + const emptyArrayFixtureDir = join(FIXTURES_DIR, 'bruno-empty-array'); + mkdirSync(emptyArrayFixtureDir, { recursive: true }); + + // 폴더 구조 생성 + const testFolder = join(emptyArrayFixtureDir, 'test'); + mkdirSync(testFolder, { recursive: true }); + + const emptyArrayFile = join(testFolder, 'empty-array.bru'); + const emptyArrayContent = `meta { + name: Empty Array Test + type: http +} + +get /test/empty-array + +docs { + \`\`\`json + { + "items": [] + } + \`\`\` +} +`; + require('fs').writeFileSync(emptyArrayFile, emptyArrayContent); + + const outputDir = join(TEST_OUTPUT_DIR, 'empty-array-output'); + execSync(`node dist/cli/index.js generate-hooks -i ${emptyArrayFixtureDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + // api.ts 파일 확인 (도메인은 폴더명 'test'가 됨) + const apiFile = join(outputDir, 'test', 'api.ts'); + assert.ok(existsSync(apiFile), 'api.ts 파일이 생성되어야 함'); + + const apiContent = readFileSync(apiFile, 'utf-8'); + assert.ok(apiContent.includes('any[]'), '빈 배열은 any[] 타입이어야 함'); + + console.log('✅ 빈 배열 any[] 타입 생성 테스트 통과'); + }); + + test('parsed.docs가 없는 경우 void 타입 생성', () => { + const noDocsFixtureDir = join(FIXTURES_DIR, 'bruno-no-docs'); + mkdirSync(noDocsFixtureDir, { recursive: true }); + + // 폴더 구조 생성 + const testFolder = join(noDocsFixtureDir, 'test'); + mkdirSync(testFolder, { recursive: true }); + + const noDocsFile = join(testFolder, 'no-docs.bru'); + const noDocsContent = `meta { + name: No Docs Test + type: http +} + +get /test/no-docs +`; + require('fs').writeFileSync(noDocsFile, noDocsContent); + + const outputDir = join(TEST_OUTPUT_DIR, 'no-docs-output'); + execSync(`node dist/cli/index.js generate-hooks -i ${noDocsFixtureDir} -o ${outputDir}`, { + cwd: join(__dirname, '..'), + }); + + // api.ts 파일 확인 (도메인은 폴더명 'test'가 됨) + const apiFile = join(outputDir, 'test', 'api.ts'); + assert.ok(existsSync(apiFile), 'api.ts 파일이 생성되어야 함'); + + const apiContent = readFileSync(apiFile, 'utf-8'); + assert.ok(apiContent.includes('void'), 'docs가 없으면 void 타입이 생성되어야 함'); + + console.log('✅ docs 없을 때 void 타입 생성 테스트 통과'); + }); +}); + +console.log('\n🎉 모든 테스트 완료!'); diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-empty-array/empty-array.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-array/empty-array.bru new file mode 100644 index 00000000..b39176c1 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-array/empty-array.bru @@ -0,0 +1,14 @@ +meta { + name: Empty Array Test + type: http +} + +get /test/empty-array + +docs { + ```json + { + "items": [] + } + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-empty-array/test/empty-array.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-array/test/empty-array.bru new file mode 100644 index 00000000..b39176c1 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-array/test/empty-array.bru @@ -0,0 +1,14 @@ +meta { + name: Empty Array Test + type: http +} + +get /test/empty-array + +docs { + ```json + { + "items": [] + } + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-empty-object/empty-response.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-object/empty-response.bru new file mode 100644 index 00000000..a0a2d4d7 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-object/empty-response.bru @@ -0,0 +1,12 @@ +meta { + name: Empty Response Test + type: http +} + +get /test/empty + +docs { + ```json + {} + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-empty-object/test/empty-response.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-object/test/empty-response.bru new file mode 100644 index 00000000..a0a2d4d7 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-empty-object/test/empty-response.bru @@ -0,0 +1,12 @@ +meta { + name: Empty Response Test + type: http +} + +get /test/empty + +docs { + ```json + {} + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-invalid-json/invalid-json.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-invalid-json/invalid-json.bru new file mode 100644 index 00000000..17252386 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-invalid-json/invalid-json.bru @@ -0,0 +1,11 @@ +meta { + name: Invalid JSON Test + type: http +} + +get /test/invalid + +docs { + 이것은 유효하지 않은 JSON입니다 + { invalid json } +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-invalid-json/test/invalid-json.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-invalid-json/test/invalid-json.bru new file mode 100644 index 00000000..17252386 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-invalid-json/test/invalid-json.bru @@ -0,0 +1,11 @@ +meta { + name: Invalid JSON Test + type: http +} + +get /test/invalid + +docs { + 이것은 유효하지 않은 JSON입니다 + { invalid json } +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-no-docs/no-docs.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-no-docs/no-docs.bru new file mode 100644 index 00000000..13daa8be --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-no-docs/no-docs.bru @@ -0,0 +1,6 @@ +meta { + name: No Docs Test + type: http +} + +get /test/no-docs diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-no-docs/test/no-docs.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-no-docs/test/no-docs.bru new file mode 100644 index 00000000..13daa8be --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-no-docs/test/no-docs.bru @@ -0,0 +1,6 @@ +meta { + name: No Docs Test + type: http +} + +get /test/no-docs diff --git "a/packages/bruno-api-typescript/tests/fixtures/bruno-v2/7) \354\226\264\353\223\234\353\257\274 [Admin]/get-list.bru" "b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/7) \354\226\264\353\223\234\353\257\274 [Admin]/get-list.bru" new file mode 100644 index 00000000..729db6de --- /dev/null +++ "b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/7) \354\226\264\353\223\234\353\257\274 [Admin]/get-list.bru" @@ -0,0 +1,56 @@ +meta { + name: 멘토 목록 조회 + type: http + seq: 1 +} + +get /mentors?region=미주권&size=3&page=1 + +headers { + Authorization: Bearer {{token}} +} + +docs { + RequestParam중, region에 올 수 있는 것들 + - 미주권 + - 아시아권 + - 중국권 + - 유럽권 + + --- + + ## 200 OK + ``` + { + "nextPageNumber": 1, + "content": [ + { + "id": 1, + "profileImageUrl": "https://example.com/image.jpg", + "nickname": "닉네임", + "country": "프랑스", + "universityName": "파리 대학교", + "term": "2025-1", + "menteeCount": 7, + "hasBadge": true, + "introduction": "안녕하세요", + "channels": [ + { + "type": "BLOG", + "url": "https://blog.example.com" + } + ], + "isApplied": true + } + ] + } + ``` + + ## 404 Not Found + + ``` + { + "message": "이름에 해당하는 지역을 찾을 수 없습니다." + } + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/create-application.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/create-application.bru new file mode 100644 index 00000000..838d14e7 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/create-application.bru @@ -0,0 +1,35 @@ +meta { + name: Create Application + type: http + seq: 2 +} + +post /applications + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "universityId": 1, + "choice": "first", + "documents": [ + "transcript.pdf", + "recommendation.pdf" + ] + } +} + +docs { + ```json + { + "id": 123, + "status": "pending", + "submittedAt": "2025-11-12T05:00:00Z", + "universityId": 1, + "choice": "first" + } + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/get-competitors.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/get-competitors.bru new file mode 100644 index 00000000..04d65062 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/get-competitors.bru @@ -0,0 +1,55 @@ +meta { + name: Get Competitors + type: http + seq: 1 +} + +get /applications/competitors + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +docs { + ```json + { + "firstChoice": [ + { + "koreanName": "데겐도르프대학", + "englishName": "Deggendorf Institute of Technology", + "studentCapacity": 150, + "region": "Bavaria", + "country": "Germany", + "gpa": "4.5", + "applicants": [ + { + "id": 1, + "name": "John Doe", + "gpa": 4.3, + "email": "john@example.com" + } + ] + } + ], + "secondChoice": [], + "thirdChoice": [] + } + ``` +} + +script:post-response { + if (res.status === 200) { + bru.setEnvVar("competitors", JSON.stringify(res.body)); + } +} + +tests { + test("should return 200", function() { + expect(res.status).to.equal(200); + }); + + test("should have firstChoice array", function() { + expect(res.body.firstChoice).to.be.an('array'); + }); +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/submit-application.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/submit-application.bru new file mode 100644 index 00000000..830ada14 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/applications/submit-application.bru @@ -0,0 +1,27 @@ +meta { + name: Submit Application + type: http + seq: 3 +} + +post /applications/submit?region=미주권&size=3&page=1 + +headers { + Authorization: Bearer {{token}} + Content-Type: application/json +} + +body:json { + { + "applicationId": 123 + } +} + +docs { + ```json + { + "success": true, + "submittedAt": "2025-11-12T05:00:00Z" + } + ``` +} diff --git a/packages/bruno-api-typescript/tests/fixtures/bruno-v2/users/get-profile.bru b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/users/get-profile.bru new file mode 100644 index 00000000..6bcff314 --- /dev/null +++ b/packages/bruno-api-typescript/tests/fixtures/bruno-v2/users/get-profile.bru @@ -0,0 +1,24 @@ +meta { + name: Get User Profile + type: http + seq: 1 +} + +get /users/profile + +headers { + Authorization: Bearer {{token}} +} + +docs { + ```json + { + "id": 1, + "username": "johndoe", + "email": "john@example.com", + "firstName": "John", + "lastName": "Doe", + "createdAt": "2025-01-01T00:00:00Z" + } + ``` +} diff --git a/packages/bruno-api-typescript/tsconfig.json b/packages/bruno-api-typescript/tsconfig.json new file mode 100644 index 00000000..1034bb59 --- /dev/null +++ b/packages/bruno-api-typescript/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "commonjs", + "lib": ["ES2022"], + "types": ["node"], + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": false, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "tests"] +} From 325df5ff72882f814c3fd63d7373639555e79c9f Mon Sep 17 00:00:00 2001 From: manNomi Date: Wed, 4 Feb 2026 02:44:28 +0900 Subject: [PATCH 06/10] =?UTF-8?q?=E2=9C=A8=20api-schema=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EB=B0=8F=20bruno=20=EB=8F=99=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++ docs/bruno-typescript-guide.md | 68 ++++++++++++++++++++++++ package.json | 4 ++ packages/api-schema/package.json | 13 +++++ packages/api-schema/src/axiosInstance.ts | 8 +++ packages/api-schema/tsconfig.json | 18 +++++++ turbo.json | 4 ++ 7 files changed, 118 insertions(+) create mode 100644 docs/bruno-typescript-guide.md create mode 100644 packages/api-schema/package.json create mode 100644 packages/api-schema/src/axiosInstance.ts create mode 100644 packages/api-schema/tsconfig.json diff --git a/.gitignore b/.gitignore index 2adbc2f3..45069428 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ **/build **/dist +# generated api schema +packages/api-schema/src/apis/ + # misc .DS_Store *.pem diff --git a/docs/bruno-typescript-guide.md b/docs/bruno-typescript-guide.md new file mode 100644 index 00000000..b1c5f2c1 --- /dev/null +++ b/docs/bruno-typescript-guide.md @@ -0,0 +1,68 @@ +# Bruno API TypeScript 사용 가이드 + +이 문서는 `bruno-api-typescript`를 사용해 공통 API 스키마를 생성하고, 어드민/웹에서 공유하는 방법을 정리합니다. + +## 1) 개념 요약 + +- Bruno `.bru` 파일을 기반으로 **TypeScript API 스키마(클라이언트 코드)** 를 자동 생성합니다. +- 생성된 코드는 `packages/api-schema/src/apis`에 위치하며, 어드민/웹 앱에서 공통으로 사용할 수 있습니다. + +## 2) 주요 명령어 + +```bash +# 스키마 동기화 (필요할 때 수동 실행) +pnpm run sync:bruno + +# 전체 빌드 시에도 자동으로 실행되도록 turbo에 연동 +pnpm run build +``` + +## 3) 스키마 생성 흐름 + +1. Bruno 정의 위치: `api-docs/Solid Connection/**/*.bru` +2. 생성 명령: `bruno-api generate-hooks` +3. 생성 결과: `packages/api-schema/src/apis/**` + +## 4) 파일/폴더 네이밍 규칙 + +`bruno-api-typescript`는 폴더/파일명 규칙에 따라 API 이름을 생성합니다. + +- 폴더명: `한글 [영문키]` → 영문키 사용 +- 파일명: `kebab-case.bru` 권장 +- 파일명에 HTTP 메서드 포함 금지 (자동 추론) + +예시: + +``` +7) 어드민 [Admin]/ + 목록 조회 [list].bru → adminApi.getList +``` + +## 5) docs 블록 작성 규칙 + +`docs` 블록의 **200 OK 응답 JSON**이 타입 생성의 기준이 됩니다. + +```bru +docs { + ## 200 OK + \`\`\`json + { + "id": 1, + "name": "example" + } + \`\`\` +} +``` + +### 주의사항 + +- 빈 배열은 `any[]`로 추론될 수 있으니, 최소 1개 요소를 포함하세요. +- `null`만 있는 값은 `null` 타입으로 고정됩니다. + +## 6) 프로젝트 구성 (적용 결과) + +- 공통 스키마 패키지: `packages/api-schema` +- 스키마 동기화 스크립트: `sync:bruno` +- Turbo task: `sync:bruno` + +필요 시 어드민/웹에서 `packages/api-schema`를 의존성으로 추가해 사용합니다. diff --git a/package.json b/package.json index a0de9467..eed44686 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,15 @@ "scripts": { "dev": "turbo dev", "build": "turbo build", + "sync:bruno": "turbo run sync:bruno", "lint": "turbo lint", "typecheck": "turbo typecheck", "ci:check": "turbo ci:check", "prepare": "husky" }, + "pnpm": { + "onlyBuiltDependencies": ["bruno-api-typescript"] + }, "devDependencies": { "@biomejs/biome": "^2.3.11", "@commitlint/cli": "^20.2.0", diff --git a/packages/api-schema/package.json b/packages/api-schema/package.json new file mode 100644 index 00000000..95b7928c --- /dev/null +++ b/packages/api-schema/package.json @@ -0,0 +1,13 @@ +{ + "name": "@solid-connect/api-schema", + "version": "0.0.0", + "private": true, + "scripts": { + "sync:bruno": "pnpm -C ../bruno-api-typescript run build && node ../bruno-api-typescript/dist/cli/index.js generate-hooks -i \"../../../api-docs/Solid Connection\" -o \"./src/apis\" --axios-path \"../axiosInstance\"", + "build": "pnpm run sync:bruno", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "axios": "^1.6.7" + } +} diff --git a/packages/api-schema/src/axiosInstance.ts b/packages/api-schema/src/axiosInstance.ts new file mode 100644 index 00000000..daadd834 --- /dev/null +++ b/packages/api-schema/src/axiosInstance.ts @@ -0,0 +1,8 @@ +import axios, { type AxiosInstance } from "axios"; + +const baseURL = process.env.NEXT_PUBLIC_API_SERVER_URL; + +export const axiosInstance: AxiosInstance = axios.create({ + baseURL, + withCredentials: true, +}); diff --git a/packages/api-schema/tsconfig.json b/packages/api-schema/tsconfig.json new file mode 100644 index 00000000..f3b5b283 --- /dev/null +++ b/packages/api-schema/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "CommonJS", + "moduleResolution": "Node", + "rootDir": "src", + "outDir": "dist", + "baseUrl": ".", + "paths": { + "../axiosInstance": ["src/axiosInstance.ts"] + }, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts"], + "exclude": ["src/apis/**"] +} diff --git a/turbo.json b/turbo.json index af2eed45..693afe3d 100644 --- a/turbo.json +++ b/turbo.json @@ -7,6 +7,10 @@ "outputs": [".next/**", "!.next/cache/**", "dist/**", ".output/**"], "env": ["NODE_ENV", "NEXT_PUBLIC_*"] }, + "sync:bruno": { + "outputs": ["src/apis/**"], + "cache": false + }, "lint": { "dependsOn": ["^lint"], "outputs": [] From f74c5a731333b74e6369267300947bdae8e4dbb6 Mon Sep 17 00:00:00 2001 From: manNomi Date: Wed, 4 Feb 2026 02:45:36 +0900 Subject: [PATCH 07/10] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20zod=20=EB=B0=8F=20@h?= =?UTF-8?q?ookform/resolvers=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/package.json | 4 +- pnpm-lock.yaml | 3915 ++--------------------------------------- 2 files changed, 137 insertions(+), 3782 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 32c14923..6ab77f8c 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -14,7 +14,7 @@ "ci:check": "pnpm run lint:check && pnpm run typecheck" }, "dependencies": { - "@hookform/resolvers": "^5.1.1", + "@hookform/resolvers": "^5.2.2", "@next/third-parties": "^14.2.4", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-label": "^2.1.2", @@ -42,7 +42,7 @@ "sockjs-client": "^1.6.1", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", - "zod": "^4.0.5", + "zod": "^4.0.0", "zustand": "^5.0.7" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7ff4448..15b70bb7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,135 +24,26 @@ importers: specifier: ^2.3.0 version: 2.7.5 - apps/admin: - dependencies: - '@radix-ui/react-label': - specifier: ^2.1.2 - version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': - specifier: ^1.2.4 - version: 1.2.4(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-tabs': - specifier: ^1.1.13 - version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tailwindcss/vite': - specifier: ^4.0.6 - version: 4.1.18(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - '@tanstack/react-devtools': - specifier: ^0.7.0 - version: 0.7.11(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) - '@tanstack/react-router': - specifier: ^1.132.0 - version: 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-router-devtools': - specifier: ^1.132.0 - version: 1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.0)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-router-ssr-query': - specifier: ^1.131.7 - version: 1.158.0(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.4))(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-start': - specifier: ^1.132.0 - version: 1.158.0(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1) - '@tanstack/router-plugin': - specifier: ^1.132.0 - version: 1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1) - axios: - specifier: ^1.6.7 - version: 1.13.2 - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - date-fns: - specifier: ^4.1.0 - version: 4.1.0 - lucide-react: - specifier: ^0.561.0 - version: 0.561.0(react@19.2.4) - nitro: - specifier: npm:nitro-nightly@latest - version: nitro-nightly@3.0.1-20260202-124820-1954b824(chokidar@3.6.0)(lru-cache@11.2.5)(rollup@4.55.1)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - react: - specifier: ^19.2.0 - version: 19.2.4 - react-dom: - specifier: ^19.2.0 - version: 19.2.4(react@19.2.4) - sonner: - specifier: ^2.0.7 - version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - tailwind-merge: - specifier: ^3.0.2 - version: 3.4.0 - tailwindcss: - specifier: ^4.0.6 - version: 4.1.18 - vite-tsconfig-paths: - specifier: ^6.0.2 - version: 6.0.5(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - devDependencies: - '@biomejs/biome': - specifier: 2.2.4 - version: 2.2.4 - '@tanstack/devtools-vite': - specifier: ^0.3.11 - version: 0.3.12(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - '@testing-library/dom': - specifier: ^10.4.0 - version: 10.4.1 - '@testing-library/react': - specifier: ^16.2.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@types/node': - specifier: ^22.10.2 - version: 22.19.7 - '@types/react': - specifier: ^19.2.0 - version: 19.2.10 - '@types/react-dom': - specifier: ^19.2.0 - version: 19.2.3(@types/react@19.2.10) - '@vitejs/plugin-react': - specifier: ^5.0.4 - version: 5.1.3(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - jsdom: - specifier: ^27.0.0 - version: 27.4.0 - typescript: - specifier: ^5.7.2 - version: 5.9.3 - vite: - specifier: ^7.1.7 - version: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/node@22.19.7)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - web-vitals: - specifier: ^5.1.0 - version: 5.1.0 - apps/web: dependencies: '@hookform/resolvers': - specifier: ^5.1.1 + specifier: ^5.2.2 version: 5.2.2(react-hook-form@7.71.1(react@18.3.1)) '@next/third-parties': specifier: ^14.2.4 version: 14.2.35(next@14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@radix-ui/react-checkbox': specifier: ^1.1.4 - version: 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.3.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-label': specifier: ^2.1.2 - version: 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-progress': specifier: ^1.1.2 - version: 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-select': specifier: ^2.1.6 - version: 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.2.6(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@react-google-maps/api': specifier: ^2.19.2 version: 2.20.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -171,9 +62,6 @@ importers: '@tanstack/react-virtual': specifier: ^3.13.12 version: 3.13.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@vercel/speed-insights': - specifier: ^1.3.1 - version: 1.3.1(next@14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) axios: specifier: ^1.6.7 version: 1.13.2 @@ -218,13 +106,13 @@ importers: version: 3.4.0 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.19(tsx@4.21.0)) + version: 1.0.7(tailwindcss@3.4.19(yaml@2.8.2)) zod: - specifier: ^4.0.5 - version: 4.3.5 + specifier: ^4.0.0 + version: 4.3.6 zustand: specifier: ^5.0.7 - version: 5.0.10(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + version: 5.0.10(@types/react@18.3.27)(react@18.3.1) devDependencies: '@svgr/webpack': specifier: ^8.1.0 @@ -233,11 +121,8 @@ importers: specifier: ^20.11.19 version: 20.19.30 '@types/react': - specifier: 18.3.27 + specifier: ^18.2.55 version: 18.3.27 - '@types/react-dom': - specifier: 18.3.7 - version: 18.3.7(@types/react@18.3.27) autoprefixer: specifier: ^10.4.20 version: 10.4.23(postcss@8.5.6) @@ -249,18 +134,38 @@ importers: version: 8.5.6 tailwindcss: specifier: ^3.4.10 - version: 3.4.19(tsx@4.21.0) + version: 3.4.19(yaml@2.8.2) typescript: specifier: ^5.3.3 version: 5.9.3 - packages/config: {} + packages/api-schema: + dependencies: + axios: + specifier: ^1.6.7 + version: 1.13.2 + + packages/bruno-api-typescript: + dependencies: + commander: + specifier: ^11.1.0 + version: 11.1.0 + glob: + specifier: ^10.3.10 + version: 10.5.0 + yaml: + specifier: ^2.3.4 + version: 2.8.2 + devDependencies: + '@types/node': + specifier: ^20.10.6 + version: 20.19.30 + typescript: + specifier: ^5.3.3 + version: 5.9.3 packages: - '@acemir/cssom@0.9.31': - resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -271,27 +176,10 @@ packages: '@apm-js-collab/tracing-hooks@0.3.1': resolution: {integrity: sha512-Vu1CbmPURlN5fTboVuKMoJjbO5qcq9fA5YXpskx3dXe/zTBvjODFoerw+69rVBlRLrJpwPqSDqEuJDEKIrTldw==} - '@asamuzakjp/css-color@4.1.1': - resolution: {integrity: sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==} - - '@asamuzakjp/dom-selector@6.7.7': - resolution: {integrity: sha512-8CO/UQ4tzDd7ula+/CVimJIVWez99UJlbMyIgk8xOnhAVPKLnBZmUFYVgugS441v2ZqUq5EnSh6B0Ua0liSFAA==} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.6': resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} engines: {node: '>=6.9.0'} @@ -300,18 +188,10 @@ packages: resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.28.6': resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.0': - resolution: {integrity: sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==} - engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -404,11 +284,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} @@ -727,18 +602,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.28.6': resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} engines: {node: '>=6.9.0'} @@ -852,10 +715,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} - engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -864,118 +723,57 @@ packages: resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - '@babel/types@7.28.6': resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@biomejs/biome@2.2.4': - resolution: {integrity: sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==} - engines: {node: '>=14.21.3'} - hasBin: true - '@biomejs/biome@2.3.12': resolution: {integrity: sha512-AR7h4aSlAvXj7TAajW/V12BOw2EiS0AqZWV5dGozf4nlLoUF/ifvD0+YgKSskT0ylA6dY1A8AwgP8kZ6yaCQnA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.2.4': - resolution: {integrity: sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [darwin] - '@biomejs/cli-darwin-arm64@2.3.12': resolution: {integrity: sha512-cO6fn+KiMBemva6EARDLQBxeyvLzgidaFRJi8G7OeRqz54kWK0E+uSjgFaiHlc3DZYoa0+1UFE8mDxozpc9ieg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.2.4': - resolution: {integrity: sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [darwin] - '@biomejs/cli-darwin-x64@2.3.12': resolution: {integrity: sha512-/fiF/qmudKwSdvmSrSe/gOTkW77mHHkH8Iy7YC2rmpLuk27kbaUOPa7kPiH5l+3lJzTUfU/t6x1OuIq/7SGtxg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.2.4': - resolution: {integrity: sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [linux] - '@biomejs/cli-linux-arm64-musl@2.3.12': resolution: {integrity: sha512-aqkeSf7IH+wkzFpKeDVPSXy9uDjxtLpYA6yzkYsY+tVjwFFirSuajHDI3ul8en90XNs1NA0n8kgBrjwRi5JeyA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.2.4': - resolution: {integrity: sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [linux] - '@biomejs/cli-linux-arm64@2.3.12': resolution: {integrity: sha512-nbOsuQROa3DLla5vvsTZg+T5WVPGi9/vYxETm9BOuLHBJN3oWQIg3MIkE2OfL18df1ZtNkqXkH6Yg9mdTPem7A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.2.4': - resolution: {integrity: sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [linux] - '@biomejs/cli-linux-x64-musl@2.3.12': resolution: {integrity: sha512-kVGWtupRRsOjvw47YFkk5mLiAdpCPMWBo1jOwAzh+juDpUb2sWarIp+iq+CPL1Wt0LLZnYtP7hH5kD6fskcxmg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.2.4': - resolution: {integrity: sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [linux] - '@biomejs/cli-linux-x64@2.3.12': resolution: {integrity: sha512-CQtqrJ+qEEI8tgRSTjjzk6wJAwfH3wQlkIGsM5dlecfRZaoT+XCms/mf7G4kWNexrke6mnkRzNy6w8ebV177ow==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.2.4': - resolution: {integrity: sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [win32] - '@biomejs/cli-win32-arm64@2.3.12': resolution: {integrity: sha512-Re4I7UnOoyE4kHMqpgtG6UvSBGBbbtvsOvBROgCCoH7EgANN6plSQhvo2W7OCITvTp7gD6oZOyZy72lUdXjqZg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.2.4': - resolution: {integrity: sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [win32] - '@biomejs/cli-win32-x64@2.3.12': resolution: {integrity: sha512-qqGVWqNNek0KikwPZlOIoxtXgsNGsX+rgdEzgw82Re8nF02W+E2WokaQhpF5TdBh/D/RQ3TLppH+otp6ztN0lw==} engines: {node: '>=14.21.3'} @@ -1051,211 +849,6 @@ packages: resolution: {integrity: sha512-VmIFV/JkBRhDRRv7N5B7zEUkNZIx9Mp+8Pe65erz0rKycXLsi8Epcw0XJ+btSeRXgTzE7DyOyA9bkJ9mn/yqVQ==} engines: {node: '>=v18'} - '@csstools/color-helpers@5.1.0': - resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} - engines: {node: '>=18'} - - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-color-parser@3.1.0': - resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-syntax-patches-for-csstree@1.0.26': - resolution: {integrity: sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==} - - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@emnapi/core@1.8.1': - resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} - - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} - - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - - '@esbuild/aix-ppc64@0.27.2': - resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.2': - resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.2': - resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.2': - resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.2': - resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.2': - resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.2': - resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.2': - resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.2': - resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.2': - resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.2': - resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.2': - resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.2': - resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.2': - resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.2': - resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.2': - resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.2': - resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.2': - resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.2': - resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.2': - resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.2': - resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.2': - resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.2': - resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.2': - resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.2': - resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.2': - resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@exodus/bytes@1.11.0': - resolution: {integrity: sha512-wO3vd8nsEHdumsXrjGO/v4p6irbg7hy9kvIeR6i2AwylZSk4HJdWgL0FNaVquW1+AweJcdvU1IEpuIWk/WaPnA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@noble/hashes': ^1.8.0 || ^2.0.0 - peerDependenciesMeta: - '@noble/hashes': - optional: true - '@fastify/busboy@3.2.0': resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==} @@ -1372,9 +965,6 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - '@next/env@14.2.35': resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} @@ -1450,22 +1040,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oozcitak/dom@2.0.2': - resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} - engines: {node: '>=20.0'} - - '@oozcitak/infra@2.0.2': - resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==} - engines: {node: '>=20.0'} - - '@oozcitak/url@3.0.0': - resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==} - engines: {node: '>=20.0'} - - '@oozcitak/util@10.0.0': - resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} - engines: {node: '>=20.0'} - '@opentelemetry/api-logs@0.208.0': resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} engines: {node: '>=8.0.0'} @@ -1656,261 +1230,23 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-minify/binding-android-arm-eabi@0.112.0': - resolution: {integrity: sha512-m7TGBR2hjsBJIN9UJ909KBoKsuogo6CuLsHKvUIBXdjI0JVHP8g4ZHeB+BJpGn5LJdeSGDfz9MWiuXrZDRzunw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxc-minify/binding-android-arm64@0.112.0': - resolution: {integrity: sha512-RvxOOkzvP5NeeoraBtgNJSBqO+XzlS7DooxST/drAXCfO52GsmxVB1N7QmifrsTYtH8GC2z3DTFjZQ1w/AJOWg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} - '@oxc-minify/binding-darwin-arm64@0.112.0': - resolution: {integrity: sha512-hDslO3uVHza3kB9zkcsi25JzN65Gj5ZYty0OvylS11Mhg9ydCYxAzfQ/tISHW/YmV1NRUJX8+GGqM1cKmrHaTA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] + '@prisma/instrumentation@6.19.0': + resolution: {integrity: sha512-QcuYy25pkXM8BJ37wVFBO7Zh34nyRV1GOb2n3lPkkbRYfl4hWl3PTcImP41P0KrzVXfa/45p6eVCos27x3exIg==} + peerDependencies: + '@opentelemetry/api': ^1.8 - '@oxc-minify/binding-darwin-x64@0.112.0': - resolution: {integrity: sha512-mWA2Y5bUyNoGM+gSGGHesgtQ3LDWgpRe4zDGkBDovxNIiDLBXqu/7QcuS+G918w8oG9VYm1q1iinILer/2pD1Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} - '@oxc-minify/binding-freebsd-x64@0.112.0': - resolution: {integrity: sha512-T7fsegxcy82xS0jWPXkz/BMhrkb3D7YOCiV0R9pDksjaov+iIFoNEWAoBsaC5NtpdzkX+bmffwDpu336EIfEeg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} - '@oxc-minify/binding-linux-arm-gnueabihf@0.112.0': - resolution: {integrity: sha512-yePavbIilAcpVYc8vRsDCn3xJxHMXDZIiamyH9fuLosAHNELcLib4/JR4fhDk4NmHVagQH3kRhsnm5Q9cm3pAw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-minify/binding-linux-arm-musleabihf@0.112.0': - resolution: {integrity: sha512-lmPWLXtW6FspERhy97iP0hwbmLtL66xI29QQ9GpHmTiE4k+zv/FaefuV/Qw+LuHnmFSYzUNrLcxh4ulOZTIP2g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-minify/binding-linux-arm64-gnu@0.112.0': - resolution: {integrity: sha512-gySS5XqU5MKs/oCjsTlVm8zb8lqcNKHEANsaRmhW2qvGKJoeGwFb6Fbq6TLCZMRuk143mLbncbverBCa1c3dog==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@oxc-minify/binding-linux-arm64-musl@0.112.0': - resolution: {integrity: sha512-IRFMZX589lr3rjG0jc8N261/7wqFq2Vl0OMrJWeFls5BF8HiB+fRYuf0Zy2CyRH6NCY2vbdDdp+QCAavQGVsGw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@oxc-minify/binding-linux-ppc64-gnu@0.112.0': - resolution: {integrity: sha512-V/69XqIW9hCUceDpcZh79oDg+F4ptEgIfKRENzYs41LRbSoJ7sNjjcW4zifqyviTvzcnXLgK4uoTyoymmNZBMQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - - '@oxc-minify/binding-linux-riscv64-gnu@0.112.0': - resolution: {integrity: sha512-zghvexySyGXGNW+MutjZN7UGTyOQl56RWMlPe1gb+knBm/+0hf9qjk7Q6ofm2tSte+vQolPfQttifGl0dP9uvQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - - '@oxc-minify/binding-linux-riscv64-musl@0.112.0': - resolution: {integrity: sha512-E4a8VUFDJPb2mPcc7J4NQQPi1ssHKF7/g4r6KD2+SBVERIaEEd3cGNqR7SG3g82/BLGV2UDoQe/WvZCkt5M/bQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - - '@oxc-minify/binding-linux-s390x-gnu@0.112.0': - resolution: {integrity: sha512-2Hx87sK3y6jBV364Mvv0zyxiITIuy26Ixenv6pK7e+4an3HgNdhAj8nk3aLoLTTSvLik5/MaGhcZGEu9tYV1aA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - - '@oxc-minify/binding-linux-x64-gnu@0.112.0': - resolution: {integrity: sha512-2MSCnEPLk9ddSouMhJo78Xy2/JbYC80OYzWdR4yWTGSULsgH3d1VXg73DSwFL8vU7Ad9oK10DioBY2ww7sQTEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - - '@oxc-minify/binding-linux-x64-musl@0.112.0': - resolution: {integrity: sha512-HAPfmQKlkVi97/zRonVE9t/kKUG3ni+mOuU1Euw+3s37KwUuOJjmcwXdclVgXKBlTkCGO0FajPwW5dAJeIXCCw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - - '@oxc-minify/binding-openharmony-arm64@0.112.0': - resolution: {integrity: sha512-bLnMojcPadYzMNpB6IAqMiTOag4etc0zbs8On73JsotO1W5c5/j/ncplpSokpEpNasKRUpHVRXpmq0KRXprNhw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxc-minify/binding-wasm32-wasi@0.112.0': - resolution: {integrity: sha512-tv7PmHYq/8QBlqMaDjsy51GF5KQkG17Yc/PsgB5OVndU34kwbQuebBIic7UfK9ygzidI8moYq3ztnu3za/rqHw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@oxc-minify/binding-win32-arm64-msvc@0.112.0': - resolution: {integrity: sha512-d+jes2jwRkcBSpcaZC6cL8GBi56Br6uAorn9dfquhWLczWL+hHSvvVrRgT1i5/6dkf5UWx2zdoEsAMiJ11w78A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxc-minify/binding-win32-ia32-msvc@0.112.0': - resolution: {integrity: sha512-TV1C3qDwj7//jNIi5tnNRhReSUgtaRQKi5KobDE6zVAc5gjeuBA8G2qizS9ziXlf/I0dlelrGmGMMDJmH9ekWg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxc-minify/binding-win32-x64-msvc@0.112.0': - resolution: {integrity: sha512-LML2Gld6VY8/+7a3VH4k1qngsBXvTkXgbmYgSYwaElqtiQiYaAcXfi0XKOUGe3k3GbBK4juAGixC31CrdFHAQw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@oxc-transform/binding-android-arm-eabi@0.112.0': - resolution: {integrity: sha512-r4LuBaPnOAi0eUOBNi880Fm2tO2omH7N1FRrL6+nyz/AjQ+QPPLtoyZJva0O+sKi1buyN/7IzM5p9m+5ANSDbg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxc-transform/binding-android-arm64@0.112.0': - resolution: {integrity: sha512-ve46vQcQrY8eGe8990VSlS9gkD+AogJqbtfOkeua+5sQGQTDgeIRRxOm7ktCo19uZc2bEBwXRJITgosd+NRVmQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxc-transform/binding-darwin-arm64@0.112.0': - resolution: {integrity: sha512-ddbmLU3Tr+i7MOynfwAXxUXud3SjJKlv7XNjaq08qiI8Av/QvhXVGc2bMhXkWQSMSBUeTDoiughKjK+Zsb6y/A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxc-transform/binding-darwin-x64@0.112.0': - resolution: {integrity: sha512-TKvmNw96jQZPqYb4pRrzLFDailNB3YS14KNn+x2hwRbqc6CqY96S9PYwyOpVpYdxfoRjYO9WgX9SoS+62a1DPA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxc-transform/binding-freebsd-x64@0.112.0': - resolution: {integrity: sha512-YPMkSCDaelO8HHYRMYjm+Q+IfkfIbdtQzwPuasItYkq8UUkNeHNPheNh2JkvQa3c+io3E9ePOgHQ2yihpk7o/Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxc-transform/binding-linux-arm-gnueabihf@0.112.0': - resolution: {integrity: sha512-nA7kzQGNEpuTRknst/IJ3l8hqmDmEda3aun6jkXgp7gKxESjuHeaNH04mKISxvJ7fIacvP2g/wtTSnm4u5jL8Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-transform/binding-linux-arm-musleabihf@0.112.0': - resolution: {integrity: sha512-w8GuLmckKlGc3YujaZKhtbFxziCcosvM2l9GnQjCb/yENWLGDiyQOy0BTAgPGdJwpYTiOeJblEXSuXYvlE1Ong==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-transform/binding-linux-arm64-gnu@0.112.0': - resolution: {integrity: sha512-9LwwGnJ8+WT0rXcrI8M0RJtDNt91eMqcDPPEvJxhRFHIMcHTy5D5xT+fOl3Us0yMqKo3HUWkbfUYqAp4GoZ3Jw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@oxc-transform/binding-linux-arm64-musl@0.112.0': - resolution: {integrity: sha512-Lg6VOuSd3oXv7J0eGywgqh/086h+qQzIBOD+47pYKMTTJcbDe+f3h/RgGoMKJE5HhiwT5sH1aGEJfIfaYUiVSw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@oxc-transform/binding-linux-ppc64-gnu@0.112.0': - resolution: {integrity: sha512-PXzmj82o1moA4IGphYImTRgc2youTi4VRfyFX3CHwLjxPcQ5JtcsgbDt4QUdOzXZ+zC07s5jf2ZzhRapEOlj2w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - - '@oxc-transform/binding-linux-riscv64-gnu@0.112.0': - resolution: {integrity: sha512-vhJsMsVH/6xwa3bt1LGts33FXUkGjaEGDwsRyp4lIfOjSfQVWMtCmWMFNaA0dW9FVWdD2Gt2fSFBSZ+azDxlpg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - - '@oxc-transform/binding-linux-riscv64-musl@0.112.0': - resolution: {integrity: sha512-cXWFb7z+2IjFUEcXtRwluq9oEG5qnyFCjiu3SWrgYNcWwPdHusv3I/7K5/CTbbi4StoZ5txbi7/iSfDHNyWuRw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - - '@oxc-transform/binding-linux-s390x-gnu@0.112.0': - resolution: {integrity: sha512-eEFu4SRqJTJ20/88KRWmp+jpHKAw0Y1DsnSgpEeXyBIIcsOaLIUMU/TfYWUmqRbvbMV9rmOmI3kp5xWYUq6kSQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - - '@oxc-transform/binding-linux-x64-gnu@0.112.0': - resolution: {integrity: sha512-ST1MDT+TlOyZ1c5btrGinRSUW2Jf4Pa+0gdKwsyjDSOC3dxy2ZNkN3mosTf4ywc3J+mxfYKqtjs7zSwHz03ILA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - - '@oxc-transform/binding-linux-x64-musl@0.112.0': - resolution: {integrity: sha512-ISQoA3pD4cyTGpf9sXXeerH6pL2L6EIpdy6oAy2ttkswyVFDyQNVOVIGIdLZDgbpmqGljxZnWqt/J/N68pQaig==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - - '@oxc-transform/binding-openharmony-arm64@0.112.0': - resolution: {integrity: sha512-UOGVrGIv7yLJovyEXEyUTADuLq98vd/cbMHFLJweRXD+11I8Tn4jASi4WzdsN8C3BVYGRHrXH2NlSBmhz33a4g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxc-transform/binding-wasm32-wasi@0.112.0': - resolution: {integrity: sha512-XIX7Gpq9koAvzBVHDlVFHM79r5uOVK6kTEsdsN4qaajpjkgtv4tdsAOKIYK6l7fUbsbE6xS+6w1+yRFrDeC1kg==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@oxc-transform/binding-win32-arm64-msvc@0.112.0': - resolution: {integrity: sha512-EgXef9kOne9BNsbYBbuRqxk2hteT0xsAGcx/VbtCBMJYNj8fANFhT271DUSOgfa4DAgrQQmsyt/Kr1aV9mpU9w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxc-transform/binding-win32-ia32-msvc@0.112.0': - resolution: {integrity: sha512-6QaB0qjNaou2YR+blncHdw7j0e26IOwOIjLbhVGDeuf9+4rjJeiqRXJ2hOtCcS4zblnao/MjdgQuZ3fM0nl+Kw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxc-transform/binding-win32-x64-msvc@0.112.0': - resolution: {integrity: sha512-FRKYlY959QeqRPx9kXs0HjU2xuXPT1cdF+vvA200D9uAX/KLcC34MwRqUKTYml4kCc2Vf/P2pBR9cQuBm3zECQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@prisma/instrumentation@6.19.0': - resolution: {integrity: sha512-QcuYy25pkXM8BJ37wVFBO7Zh34nyRV1GOb2n3lPkkbRYfl4hWl3PTcImP41P0KrzVXfa/45p6eVCos27x3exIg==} - peerDependencies: - '@opentelemetry/api': ^1.8 - - '@protobufjs/aspromise@1.1.2': - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} - - '@protobufjs/base64@1.1.2': - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} - - '@protobufjs/codegen@2.0.4': - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} '@protobufjs/eventemitter@1.1.0': resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} @@ -2149,19 +1485,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-select@2.2.6': resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} peerDependencies: @@ -2193,19 +1516,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-use-callback-ref@1.1.1': resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: @@ -2306,12 +1616,6 @@ packages: '@react-google-maps/marker-clusterer@2.20.0': resolution: {integrity: sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==} - '@rolldown/pluginutils@1.0.0-beta.40': - resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} - - '@rolldown/pluginutils@1.0.0-rc.2': - resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} - '@rollup/plugin-commonjs@28.0.1': resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} engines: {node: '>=16.0.0 || 14 >= 14.17'} @@ -2587,36 +1891,6 @@ packages: peerDependencies: webpack: '>=4.40.0' - '@solid-primitives/event-listener@2.4.3': - resolution: {integrity: sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/keyboard@1.3.3': - resolution: {integrity: sha512-9dQHTTgLBqyAI7aavtO+HnpTVJgWQA1ghBSrmLtMu1SMxLPDuLfuNr+Tk5udb4AL4Ojg7h9JrKOGEEDqsJXWJA==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/resize-observer@2.1.3': - resolution: {integrity: sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/rootless@1.5.2': - resolution: {integrity: sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/static-store@0.1.2': - resolution: {integrity: sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw==} - peerDependencies: - solid-js: ^1.6.12 - - '@solid-primitives/utils@6.3.2': - resolution: {integrity: sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ==} - peerDependencies: - solid-js: ^1.6.12 - '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} @@ -2707,153 +1981,12 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} - - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} - - '@tailwindcss/vite@4.1.18': - resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 - - '@tanstack/devtools-client@0.0.3': - resolution: {integrity: sha512-kl0r6N5iIL3t9gGDRAv55VRM3UIyMKVH83esRGq7xBjYsRLe/BeCIN2HqrlJkObUXQMKhy7i8ejuGOn+bDqDBw==} - engines: {node: '>=18'} - - '@tanstack/devtools-client@0.0.5': - resolution: {integrity: sha512-hsNDE3iu4frt9cC2ppn1mNRnLKo2uc1/1hXAyY9z4UYb+o40M2clFAhiFoo4HngjfGJDV3x18KVVIq7W4Un+zA==} - engines: {node: '>=18'} - - '@tanstack/devtools-event-bus@0.3.3': - resolution: {integrity: sha512-lWl88uLAz7ZhwNdLH6A3tBOSEuBCrvnY9Fzr5JPdzJRFdM5ZFdyNWz1Bf5l/F3GU57VodrN0KCFi9OA26H5Kpg==} - engines: {node: '>=18'} - - '@tanstack/devtools-event-client@0.3.5': - resolution: {integrity: sha512-RL1f5ZlfZMpghrCIdzl6mLOFLTuhqmPNblZgBaeKfdtk5rfbjykurv+VfYydOFXj0vxVIoA2d/zT7xfD7Ph8fw==} - engines: {node: '>=18'} - - '@tanstack/devtools-event-client@0.4.0': - resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==} - engines: {node: '>=18'} - - '@tanstack/devtools-ui@0.4.4': - resolution: {integrity: sha512-5xHXFyX3nom0UaNfiOM92o6ziaHjGo3mcSGe2HD5Xs8dWRZNpdZ0Smd0B9ddEhy0oB+gXyMzZgUJb9DmrZV0Mg==} - engines: {node: '>=18'} - peerDependencies: - solid-js: '>=1.9.7' - - '@tanstack/devtools-vite@0.3.12': - resolution: {integrity: sha512-fGJgu4xUhKmGk+a+/aHD8l5HKVk6+ObA+6D3YC3xCXbai/YmaGhztqcZf1tKUqjZyYyQLHsjqmKzvJgVpQP1jw==} - engines: {node: '>=18'} - peerDependencies: - vite: ^6.0.0 || ^7.0.0 - - '@tanstack/devtools@0.7.0': - resolution: {integrity: sha512-AlAoCqJhWLg9GBEaoV1g/j+X/WA1aJSWOsekxeuZpYeS2hdVuKAjj04KQLUMJhtLfNl2s2E+TCj7ZRtWyY3U4w==} - engines: {node: '>=18'} - peerDependencies: - solid-js: '>=1.9.7' - - '@tanstack/history@1.154.14': - resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==} - engines: {node: '>=12'} - '@tanstack/query-core@5.90.19': resolution: {integrity: sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==} '@tanstack/query-devtools@5.92.0': resolution: {integrity: sha512-N8D27KH1vEpVacvZgJL27xC6yPFUy0Zkezn5gnB3L3gRCxlDeSuiya7fKge8Y91uMTnC8aSxBQhcK6ocY7alpQ==} - '@tanstack/react-devtools@0.7.11': - resolution: {integrity: sha512-a2Lmz8x+JoDrsU6f7uKRcyyY+k8mA/n5mb9h7XJ3Fz/y3+sPV9t7vAW1s5lyNkQyyDt6V1Oim99faLthoJSxMw==} - engines: {node: '>=18'} - peerDependencies: - '@types/react': '>=16.8' - '@types/react-dom': '>=16.8' - react: '>=16.8' - react-dom: '>=16.8' - '@tanstack/react-query-devtools@5.91.2': resolution: {integrity: sha512-ZJ1503ay5fFeEYFUdo7LMNFzZryi6B0Cacrgr2h1JRkvikK1khgIq6Nq2EcblqEdIlgB/r7XDW8f8DQ89RuUgg==} peerDependencies: @@ -2865,169 +1998,14 @@ packages: peerDependencies: react: ^18 || ^19 - '@tanstack/react-router-devtools@1.158.0': - resolution: {integrity: sha512-uhciBlsPW67xbDCFyc2RQS00OergfNXYxendGUO2HGy4uTr79aQSCb4l6v+sdlPwUTlzwkAtM6e1illIexF15Q==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/react-router': ^1.158.0 - '@tanstack/router-core': ^1.158.0 - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - peerDependenciesMeta: - '@tanstack/router-core': - optional: true - - '@tanstack/react-router-ssr-query@1.158.0': - resolution: {integrity: sha512-9krJIPtGQVec7edA710xT4UJimSvIh0gFvJLd4jCIKfPV0Lc00fjmcBlpYKSK33BsefztG6HXVc2nR8nX+8Teg==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/query-core': '>=5.90.0' - '@tanstack/react-query': '>=5.90.0' - '@tanstack/react-router': '>=1.127.0' - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - - '@tanstack/react-router@1.158.0': - resolution: {integrity: sha512-kvTaO6zjq9WWPyo1wwSZx95AjJ9KOvu23cOMgKeDdDQWKF3Z9q3fwhToKMKJoC11T2Vuivz+o/anrxCcOvdRzw==} - engines: {node: '>=12'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - - '@tanstack/react-start-client@1.158.0': - resolution: {integrity: sha512-oxo9+nFzsdiOkMFPs3HuVXola34FD2/kDfzO8wMu+KSsCwSRRhXpS7DGq/myw6AtjqiiFkNHeZqvvrlcH523Aw==} - engines: {node: '>=22.12.0'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - - '@tanstack/react-start-server@1.158.0': - resolution: {integrity: sha512-J1v8mckJIf2DHOg38XMq7X7CCOqiyLCPqKQDP8GXJ2WgjpBk6l+lemBmyhF1+76LxYWHfsQYwAg5W3cJ8+QqrQ==} - engines: {node: '>=22.12.0'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - - '@tanstack/react-start@1.158.0': - resolution: {integrity: sha512-CwfX2XGDVSwim24LWwM24ZxyposE+5Psj2e2PW4YN+AGgfdwm0+1xk9DEmDQp/Vke2OIdhnIXD/IDe7zTGpzcg==} - engines: {node: '>=22.12.0'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - vite: '>=7.0.0' - - '@tanstack/react-store@0.8.0': - resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/react-virtual@3.13.18': resolution: {integrity: sha512-dZkhyfahpvlaV0rIKnvQiVoWPyURppl6w4m9IwMDpuIjcJ1sD9YGWrt0wISvgU7ewACXx2Ct46WPgI6qAD4v6A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/router-core@1.158.0': - resolution: {integrity: sha512-dRMcWY0UB/6OZqSCx/7iUvom0ol18rHSQladygVT8mlth7uxYx3n5BNse8C03efIE8y1Bx+VDOBAKpAZ9BgKog==} - engines: {node: '>=12'} - - '@tanstack/router-devtools-core@1.158.0': - resolution: {integrity: sha512-8FUKfjh8Xz9T9O5yYaiVE0Va5aCMncQyVPKb7yy5M/buDnx9Kh0bPjw/eUZJWftOyxW6/WeR605yjOdx/PnqNw==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/router-core': ^1.158.0 - csstype: ^3.0.10 - peerDependenciesMeta: - csstype: - optional: true - - '@tanstack/router-generator@1.158.0': - resolution: {integrity: sha512-hVkXQSN/fMD9q3Zn3wNa4PV0Y9VNwQB2bLaecA5i4vc43GX75vmgyiKoMr44BJheUssfVoL/po9a/7sv+N6lKA==} - engines: {node: '>=12'} - - '@tanstack/router-plugin@1.158.0': - resolution: {integrity: sha512-FxTOo/icU373jlOu9nlzR0B1vqc47tKZLw3HwOQwCBL4P4EihOBz+L7dcGyKR8bRBL0rCRWvHQTSHNMOr+fGYQ==} - engines: {node: '>=12'} - peerDependencies: - '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.158.0 - vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' - vite-plugin-solid: ^2.11.10 - webpack: '>=5.92.0' - peerDependenciesMeta: - '@rsbuild/core': - optional: true - '@tanstack/react-router': - optional: true - vite: - optional: true - vite-plugin-solid: - optional: true - webpack: - optional: true - - '@tanstack/router-ssr-query-core@1.158.0': - resolution: {integrity: sha512-OFtFCYmuVEDo1XcPlcj4HLYZXnmLiX8akJU/4qgE3wjFL8laZCOR6yll9z1Sid8nCaztcD8AKjqzFh0KOGX2Hg==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/query-core': '>=5.90.0' - '@tanstack/router-core': '>=1.127.0' - - '@tanstack/router-utils@1.158.0': - resolution: {integrity: sha512-qZ76eaLKU6Ae9iI/mc5zizBX149DXXZkBVVO3/QRIll79uKLJZHQlMKR++2ba7JsciBWz1pgpIBcCJPE9S0LVg==} - engines: {node: '>=12'} - - '@tanstack/start-client-core@1.158.0': - resolution: {integrity: sha512-nGuzFEuC+yEMd7inPP185K+tcPlHk8rcg8x/t2dAhytM+r4PxyRkvXrHoKMbQKGYR2CArml96UNEKXWxsAtmow==} - engines: {node: '>=22.12.0'} - - '@tanstack/start-fn-stubs@1.154.7': - resolution: {integrity: sha512-D69B78L6pcFN5X5PHaydv7CScQcKLzJeEYqs7jpuyyqGQHSUIZUjS955j+Sir8cHhuDIovCe2LmsYHeZfWf3dQ==} - engines: {node: '>=22.12.0'} - - '@tanstack/start-plugin-core@1.158.0': - resolution: {integrity: sha512-KiG4ofL1I3A2p3BJ7qhyfugyKh5KMOIURvftmVc33IWLQaSYvCzCHoyaWfvcHIELbkyFpMwd4EauZH3I80BE8A==} - engines: {node: '>=22.12.0'} - peerDependencies: - vite: '>=7.0.0' - - '@tanstack/start-server-core@1.158.0': - resolution: {integrity: sha512-C5Hgxl79fV8e0sGsFB4akFhmU3zO0FpriyBof7pSKROCEOt8hXq2QstYhb3QVR9KdzKAPR+JHg3BbEOBNUVn7Q==} - engines: {node: '>=22.12.0'} - - '@tanstack/start-storage-context@1.158.0': - resolution: {integrity: sha512-9wkbgZoMlVIFJGmCrSWeOF9sPveVOw8LwSk1YwKj4tQOXurxdOBoQMvkYy+sxcGkhK6CmGGJqsedKVHK3EZQng==} - engines: {node: '>=22.12.0'} - - '@tanstack/store@0.8.0': - resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} - - '@tanstack/virtual-core@3.13.18': - resolution: {integrity: sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==} - - '@tanstack/virtual-file-routes@1.154.7': - resolution: {integrity: sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg==} - engines: {node: '>=12'} - - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} - - '@testing-library/react@16.3.2': - resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} - engines: {node: '>=18'} - peerDependencies: - '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/virtual-core@3.13.18': + resolution: {integrity: sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==} '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} @@ -3037,39 +2015,15 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - '@types/caseless@0.12.5': resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==} - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} '@types/conventional-commits-parser@5.0.2': resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -3112,22 +2066,9 @@ packages: '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - '@types/react@18.3.27': resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} - '@types/react@19.2.10': - resolution: {integrity: sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==} - '@types/request@2.48.13': resolution: {integrity: sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==} @@ -3137,64 +2078,6 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@vercel/speed-insights@1.3.1': - resolution: {integrity: sha512-PbEr7FrMkUrGYvlcLHGkXdCkxnylCWePx7lPxxq36DNdfo9mcUjLOmqOyPDHAOgnfqgGGdmE3XI9L/4+5fr+vQ==} - peerDependencies: - '@sveltejs/kit': ^1 || ^2 - next: '>= 13' - react: ^18 || ^19 || ^19.0.0-rc - svelte: '>= 4' - vue: ^3 - vue-router: ^4 - peerDependenciesMeta: - '@sveltejs/kit': - optional: true - next: - optional: true - react: - optional: true - svelte: - optional: true - vue: - optional: true - vue-router: - optional: true - - '@vitejs/plugin-react@5.1.3': - resolution: {integrity: sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -3306,18 +2189,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} - engines: {node: '>=14'} - any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -3335,9 +2210,6 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} @@ -3345,14 +2217,6 @@ packages: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} - async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} @@ -3369,9 +2233,6 @@ packages: axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - babel-dead-code-elimination@1.0.12: - resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - babel-plugin-polyfill-corejs2@0.4.14: resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} peerDependencies: @@ -3397,9 +2258,6 @@ packages: resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} hasBin: true - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -3432,10 +2290,6 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -3455,10 +2309,6 @@ packages: caniuse-lite@1.0.30001764: resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} - chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} - engines: {node: '>=18'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -3467,17 +2317,6 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} - - cheerio-select@2.1.0: - resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} - - cheerio@1.2.0: - resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} - engines: {node: '>=20.18.1'} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -3514,6 +2353,10 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -3531,10 +2374,6 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - conventional-changelog-angular@7.0.0: resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} engines: {node: '>=16'} @@ -3551,9 +2390,6 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-es@2.0.0: - resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} - core-js-compat@3.47.0: resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} @@ -3590,14 +2426,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crossws@0.4.4: - resolution: {integrity: sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==} - peerDependencies: - srvx: '>=0.7.1' - peerDependenciesMeta: - srvx: - optional: true - css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -3609,10 +2437,6 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-what@6.2.2: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} @@ -3626,10 +2450,6 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - cssstyle@5.3.7: - resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} - engines: {node: '>=20'} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -3637,36 +2457,6 @@ packages: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} - data-urls@6.0.1: - resolution: {integrity: sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==} - engines: {node: '>=20'} - - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - - db0@0.3.4: - resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} - peerDependencies: - '@electric-sql/pglite': '*' - '@libsql/client': '*' - better-sqlite3: '*' - drizzle-orm: '*' - mysql2: '*' - sqlite3: '*' - peerDependenciesMeta: - '@electric-sql/pglite': - optional: true - '@libsql/client': - optional: true - better-sqlite3: - optional: true - drizzle-orm: - optional: true - mysql2: - optional: true - sqlite3: - optional: true - debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -3684,13 +2474,6 @@ packages: supports-color: optional: true - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -3699,30 +2482,15 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - diff@8.0.3: - resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} - engines: {node: '>=0.3.1'} - dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -3769,9 +2537,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encoding-sniffer@0.2.1: - resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} - end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -3783,14 +2548,6 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - entities@7.0.1: - resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} - engines: {node: '>=0.12'} - env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -3806,9 +2563,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} @@ -3820,11 +2574,6 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.27.2: - resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} - engines: {node: '>=18'} - hasBin: true - escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3833,11 +2582,6 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -3853,9 +2597,6 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -3872,13 +2613,6 @@ packages: resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} engines: {node: '>=12.0.0'} - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -3998,9 +2732,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.1: - resolution: {integrity: sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==} - git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} @@ -4025,14 +2756,6 @@ packages: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - goober@2.1.18: - resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} - peerDependencies: - csstype: ^3.0.10 - google-auth-library@9.15.1: resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} engines: {node: '>=14'} @@ -4056,15 +2779,6 @@ packages: resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} engines: {node: '>=14.0.0'} - h3@2.0.1-rc.11: - resolution: {integrity: sha512-2myzjCqy32c1As9TjZW9fNZXtLqNedjFSrdFy2AjFBQQ3LzrnGoDdFDYfC0tV2e4vcyfJ2Sfo/F6NQhO2Ly/Mw==} - engines: {node: '>=20.11.1'} - peerDependencies: - crossws: ^0.4.1 - peerDependenciesMeta: - crossws: - optional: true - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -4081,16 +2795,9 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} - htmlparser2@10.1.0: - resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} @@ -4101,10 +2808,6 @@ packages: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -4118,10 +2821,6 @@ packages: engines: {node: '>=18'} hasBin: true - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -4173,9 +2872,6 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -4187,10 +2883,6 @@ packages: resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} engines: {node: '>=8'} - isbot@5.1.34: - resolution: {integrity: sha512-aCMIBSKd/XPRYdiCQTLC8QHH4YT8B3JUADu+7COgYIZPvkeoMcUHMRjZLM9/7V8fCj+l7FSREc1lOPNjzogo/A==} - engines: {node: '>=18'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -4215,22 +2907,10 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdom@27.4.0: - resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -4271,79 +2951,6 @@ packages: kdbush@4.0.2: resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} - launch-editor@2.12.0: - resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==} - - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} - engines: {node: '>= 12.0.0'} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -4433,19 +3040,12 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - loupe@3.2.1: - resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.5: - resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} - engines: {node: 20 || >=22} - lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -4461,15 +3061,6 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lucide-react@0.561.0: - resolution: {integrity: sha512-Y59gMY38tl4/i0qewcqohPdEbieBy7SovpBL9IFebhc2mDd8x4PZSOsiFRkpPcOq6bj1r/mjH/Rk73gSlIJP2A==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -4487,9 +3078,6 @@ packages: mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} @@ -4569,28 +3157,6 @@ packages: sass: optional: true - nf3@0.3.7: - resolution: {integrity: sha512-wL73kyZbBoeTWlvQWQ0gQDZnqp+aNlUN5YIqsc3fv5V/06LAlwrwt+G7TpugFLJIai0AhrmnKJ2kgW0xprj+yQ==} - - nitro-nightly@3.0.1-20260202-124820-1954b824: - resolution: {integrity: sha512-0opA9HR5zNlpWmozd4gOh9mhVk6c+FJhbKg2nrMs+IK56WYDsaLGDSNYjg1Z0cvqMCCbZrafCHQBzhlFDxoytw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - rolldown: '>=1.0.0-rc.2' - rollup: ^4.57.0 - vite: ^7 || ^8 || >=8.0.0-0 - xml2js: ^0.6.2 - peerDependenciesMeta: - rolldown: - optional: true - rollup: - optional: true - vite: - optional: true - xml2js: - optional: true - no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -4625,23 +3191,9 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - ofetch@2.0.0-alpha.3: - resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==} - - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - oxc-minify@0.112.0: - resolution: {integrity: sha512-rkVSeeIRSt+RYI9uX6xonBpLUpvZyegxIg0UL87ev7YAfUqp7IIZlRjkgQN5Us1lyXD//TOo0Dcuuro/TYOWoQ==} - engines: {node: ^20.19.0 || >=22.12.0} - - oxc-transform@0.112.0: - resolution: {integrity: sha512-cIRRvZgrHfsAHrkt8LWdAX4+Do8R0MzQSfeo9yzErzHeYiuyNiP4PCTPbOy/wBXL4MYzt3ebrBa5jt3akQkKAg==} - engines: {node: ^20.19.0 || >=22.12.0} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -4669,18 +3221,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse5-htmlparser2-tree-adapter@7.1.0: - resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} - - parse5-parser-stream@7.1.2: - resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -4704,13 +3244,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -4811,15 +3344,6 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} - engines: {node: '>=14'} - hasBin: true - - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -4835,10 +3359,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -4853,24 +3373,12 @@ packages: peerDependencies: react: ^18.3.1 - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - react-hook-form@7.71.1: resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -4905,10 +3413,6 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} - read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -4920,10 +3424,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - recast@0.23.11: - resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} - engines: {node: '>= 4'} - regenerate-unicode-properties@10.2.2: resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} engines: {node: '>=4'} @@ -4965,9 +3465,6 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} @@ -4990,28 +3487,15 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rou3@0.7.12: - resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} @@ -5028,16 +3512,6 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - seroval-plugins@1.5.0: - resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==} - engines: {node: '>=10'} - peerDependencies: - seroval: ^1.0 - - seroval@1.5.0: - resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==} - engines: {node: '>=10'} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -5046,13 +3520,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -5064,15 +3531,6 @@ packages: resolution: {integrity: sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==} engines: {node: '>=12'} - solid-js@1.9.11: - resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} - - sonner@2.0.7: - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5084,29 +3542,14 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - srvx@0.10.1: - resolution: {integrity: sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg==} - engines: {node: '>=20.16.0'} - hasBin: true - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - stacktrace-parser@0.1.11: resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} engines: {node: '>=6'} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - stream-events@1.0.5: resolution: {integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==} @@ -5136,9 +3579,6 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} - strip-literal@3.1.0: - resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} @@ -5186,9 +3626,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tailwind-merge@3.4.0: resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} @@ -5202,9 +3639,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} - tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -5251,18 +3685,6 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tiny-warning@1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -5271,61 +3693,19 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} - engines: {node: '>=14.0.0'} - - tldts-core@7.0.21: - resolution: {integrity: sha512-oVOMdHvgjqyzUZH1rOESgJP1uNe2bVrfK0jUHHmiM2rpEiRbf3j4BrsIc6JigJRbHGanQwuZv/R+LTcHsw+bLA==} - - tldts@7.0.21: - resolution: {integrity: sha512-Plu6V8fF/XU6d2k8jPtlQf5F4Xx2hAin4r2C2ca7wR8NK5MbRTo9huLUWRe28f3Uk8bYZfg74tit/dSjc18xnw==} - hasBin: true - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} - engines: {node: '>=16'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} - ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - tsconfck@3.1.6: - resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} - engines: {node: '>=18.0.0'} - hasBin: true - turbo-darwin-64@2.7.5: resolution: {integrity: sha512-nN3wfLLj4OES/7awYyyM7fkU8U8sAFxsXau2bYJwAWi6T09jd87DgHD8N31zXaJ7LcpyppHWPRI2Ov9MuZEwnQ==} cpu: [x64] @@ -5369,19 +3749,9 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@7.20.0: - resolution: {integrity: sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==} - engines: {node: '>=20.18.1'} - - unenv@2.0.0-rc.24: - resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} - unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -5405,84 +3775,6 @@ packages: unplugin@1.0.1: resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} - unplugin@2.3.11: - resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} - engines: {node: '>=18.12.0'} - - unstorage@2.0.0-alpha.5: - resolution: {integrity: sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g==} - peerDependencies: - '@azure/app-configuration': ^1.9.0 - '@azure/cosmos': ^4.7.0 - '@azure/data-tables': ^13.3.1 - '@azure/identity': ^4.13.0 - '@azure/keyvault-secrets': ^4.10.0 - '@azure/storage-blob': ^12.29.1 - '@capacitor/preferences': ^6.0.3 || ^7.0.0 - '@deno/kv': '>=0.12.0' - '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 - '@planetscale/database': ^1.19.0 - '@upstash/redis': ^1.35.6 - '@vercel/blob': '>=0.27.3' - '@vercel/functions': ^2.2.12 || ^3.0.0 - '@vercel/kv': ^1.0.1 - aws4fetch: ^1.0.20 - chokidar: ^4 || ^5 - db0: '>=0.3.4' - idb-keyval: ^6.2.2 - ioredis: ^5.8.2 - lru-cache: ^11.2.2 - mongodb: ^6 || ^7 - ofetch: '*' - uploadthing: ^7.7.4 - peerDependenciesMeta: - '@azure/app-configuration': - optional: true - '@azure/cosmos': - optional: true - '@azure/data-tables': - optional: true - '@azure/identity': - optional: true - '@azure/keyvault-secrets': - optional: true - '@azure/storage-blob': - optional: true - '@capacitor/preferences': - optional: true - '@deno/kv': - optional: true - '@netlify/blobs': - optional: true - '@planetscale/database': - optional: true - '@upstash/redis': - optional: true - '@vercel/blob': - optional: true - '@vercel/functions': - optional: true - '@vercel/kv': - optional: true - aws4fetch: - optional: true - chokidar: - optional: true - db0: - optional: true - idb-keyval: - optional: true - ioredis: - optional: true - lru-cache: - optional: true - mongodb: - optional: true - ofetch: - optional: true - uploadthing: - optional: true - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -5512,11 +3804,6 @@ packages: '@types/react': optional: true - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -5532,110 +3819,13 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite-tsconfig-paths@6.0.5: - resolution: {integrity: sha512-f/WvY6ekHykUF1rWJUAbCU7iS/5QYDIugwpqJA+ttwKbxSbzNlqlE8vZSrsnxNQciUW+z6lvhlXMaEyZn9MSig==} - peerDependencies: - vite: '*' - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitefu@1.1.1: - resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 - peerDependenciesMeta: - vite: - optional: true - - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - watchpack@2.5.1: resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} - web-vitals@5.1.0: - resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - webpack-sources@3.3.3: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} @@ -5643,9 +3833,6 @@ packages: webpack-virtual-modules@0.5.0: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.104.1: resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} @@ -5664,23 +3851,6 @@ packages: resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} engines: {node: '>=0.8.0'} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - - whatwg-url@15.1.0: - resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} - engines: {node: '>=20'} - whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5689,11 +3859,6 @@ packages: engines: {node: '>= 8'} hasBin: true - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5705,29 +3870,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} - 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 - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlbuilder2@4.0.3: - resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} - engines: {node: '>=20.0'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -5742,6 +3884,11 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -5758,11 +3905,8 @@ packages: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.3.5: - resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} zustand@5.0.10: resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==} @@ -5784,8 +3928,6 @@ packages: snapshots: - '@acemir/cssom@0.9.31': {} - '@alloc/quick-lru@5.2.0': {} '@apm-js-collab/code-transformer@0.8.2': {} @@ -5798,42 +3940,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@asamuzakjp/css-color@4.1.1': - dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.5 - - '@asamuzakjp/dom-selector@6.7.7': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.5 - - '@asamuzakjp/nwsapi@2.3.9': {} - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/compat-data@7.28.6': {} '@babel/core@7.28.6': @@ -5856,26 +3968,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/generator@7.28.6': dependencies: '@babel/parser': 7.28.6 @@ -5884,14 +3976,6 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/generator@7.29.0': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.28.6 @@ -5960,15 +4044,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.6 - transitivePeerDependencies: - - supports-color - '@babel/helper-optimise-call-expression@7.27.1': dependencies: '@babel/types': 7.28.6 @@ -6023,10 +4098,6 @@ snapshots: dependencies: '@babel/types': 7.28.6 - '@babel/parser@7.29.0': - dependencies: - '@babel/types': 7.29.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 @@ -6375,16 +4446,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 @@ -6586,8 +4647,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/runtime@7.28.6': {} - '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.28.6 @@ -6606,39 +4665,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.0 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@biomejs/biome@2.2.4': - optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.2.4 - '@biomejs/cli-darwin-x64': 2.2.4 - '@biomejs/cli-linux-arm64': 2.2.4 - '@biomejs/cli-linux-arm64-musl': 2.2.4 - '@biomejs/cli-linux-x64': 2.2.4 - '@biomejs/cli-linux-x64-musl': 2.2.4 - '@biomejs/cli-win32-arm64': 2.2.4 - '@biomejs/cli-win32-x64': 2.2.4 - '@biomejs/biome@2.3.12': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.3.12 @@ -6650,51 +4681,27 @@ snapshots: '@biomejs/cli-win32-arm64': 2.3.12 '@biomejs/cli-win32-x64': 2.3.12 - '@biomejs/cli-darwin-arm64@2.2.4': - optional: true - '@biomejs/cli-darwin-arm64@2.3.12': optional: true - '@biomejs/cli-darwin-x64@2.2.4': - optional: true - '@biomejs/cli-darwin-x64@2.3.12': optional: true - '@biomejs/cli-linux-arm64-musl@2.2.4': - optional: true - '@biomejs/cli-linux-arm64-musl@2.3.12': optional: true - '@biomejs/cli-linux-arm64@2.2.4': - optional: true - '@biomejs/cli-linux-arm64@2.3.12': optional: true - '@biomejs/cli-linux-x64-musl@2.2.4': - optional: true - '@biomejs/cli-linux-x64-musl@2.3.12': optional: true - '@biomejs/cli-linux-x64@2.2.4': - optional: true - '@biomejs/cli-linux-x64@2.3.12': optional: true - '@biomejs/cli-win32-arm64@2.2.4': - optional: true - '@biomejs/cli-win32-arm64@2.3.12': optional: true - '@biomejs/cli-win32-x64@2.2.4': - optional: true - '@biomejs/cli-win32-x64@2.3.12': optional: true @@ -6808,150 +4815,32 @@ snapshots: '@types/conventional-commits-parser': 5.0.2 chalk: 5.6.2 - '@csstools/color-helpers@5.1.0': {} - - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/color-helpers': 5.1.0 - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 + '@fastify/busboy@3.2.0': {} - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-tokenizer': 3.0.4 + '@firebase/app-check-interop-types@0.3.2': {} - '@csstools/css-syntax-patches-for-csstree@1.0.26': {} + '@firebase/app-types@0.9.2': {} - '@csstools/css-tokenizer@3.0.4': {} + '@firebase/auth-interop-types@0.2.3': {} - '@emnapi/core@1.8.1': + '@firebase/component@0.6.9': dependencies: - '@emnapi/wasi-threads': 1.1.0 + '@firebase/util': 1.10.0 tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.8.1': + '@firebase/database-compat@1.0.8': dependencies: + '@firebase/component': 0.6.9 + '@firebase/database': 1.0.8 + '@firebase/database-types': 1.0.5 + '@firebase/logger': 0.4.2 + '@firebase/util': 1.10.0 tslib: 2.8.1 - optional: true - '@emnapi/wasi-threads@1.1.0': + '@firebase/database-types@1.0.5': dependencies: - tslib: 2.8.1 - optional: true - - '@esbuild/aix-ppc64@0.27.2': - optional: true - - '@esbuild/android-arm64@0.27.2': - optional: true - - '@esbuild/android-arm@0.27.2': - optional: true - - '@esbuild/android-x64@0.27.2': - optional: true - - '@esbuild/darwin-arm64@0.27.2': - optional: true - - '@esbuild/darwin-x64@0.27.2': - optional: true - - '@esbuild/freebsd-arm64@0.27.2': - optional: true - - '@esbuild/freebsd-x64@0.27.2': - optional: true - - '@esbuild/linux-arm64@0.27.2': - optional: true - - '@esbuild/linux-arm@0.27.2': - optional: true - - '@esbuild/linux-ia32@0.27.2': - optional: true - - '@esbuild/linux-loong64@0.27.2': - optional: true - - '@esbuild/linux-mips64el@0.27.2': - optional: true - - '@esbuild/linux-ppc64@0.27.2': - optional: true - - '@esbuild/linux-riscv64@0.27.2': - optional: true - - '@esbuild/linux-s390x@0.27.2': - optional: true - - '@esbuild/linux-x64@0.27.2': - optional: true - - '@esbuild/netbsd-arm64@0.27.2': - optional: true - - '@esbuild/netbsd-x64@0.27.2': - optional: true - - '@esbuild/openbsd-arm64@0.27.2': - optional: true - - '@esbuild/openbsd-x64@0.27.2': - optional: true - - '@esbuild/openharmony-arm64@0.27.2': - optional: true - - '@esbuild/sunos-x64@0.27.2': - optional: true - - '@esbuild/win32-arm64@0.27.2': - optional: true - - '@esbuild/win32-ia32@0.27.2': - optional: true - - '@esbuild/win32-x64@0.27.2': - optional: true - - '@exodus/bytes@1.11.0': {} - - '@fastify/busboy@3.2.0': {} - - '@firebase/app-check-interop-types@0.3.2': {} - - '@firebase/app-types@0.9.2': {} - - '@firebase/auth-interop-types@0.2.3': {} - - '@firebase/component@0.6.9': - dependencies: - '@firebase/util': 1.10.0 - tslib: 2.8.1 - - '@firebase/database-compat@1.0.8': - dependencies: - '@firebase/component': 0.6.9 - '@firebase/database': 1.0.8 - '@firebase/database-types': 1.0.5 - '@firebase/logger': 0.4.2 - '@firebase/util': 1.10.0 - tslib: 2.8.1 - - '@firebase/database-types@1.0.5': - dependencies: - '@firebase/app-types': 0.9.2 - '@firebase/util': 1.10.0 + '@firebase/app-types': 0.9.2 + '@firebase/util': 1.10.0 '@firebase/database@1.0.8': dependencies: @@ -7104,13 +4993,6 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': optional: true - '@napi-rs/wasm-runtime@1.1.1': - dependencies: - '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 - '@tybys/wasm-util': 0.10.1 - optional: true - '@next/env@14.2.35': {} '@next/swc-darwin-arm64@14.2.33': @@ -7158,23 +5040,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@oozcitak/dom@2.0.2': - dependencies: - '@oozcitak/infra': 2.0.2 - '@oozcitak/url': 3.0.0 - '@oozcitak/util': 10.0.0 - - '@oozcitak/infra@2.0.2': - dependencies: - '@oozcitak/util': 10.0.0 - - '@oozcitak/url@3.0.0': - dependencies: - '@oozcitak/infra': 2.0.2 - '@oozcitak/util': 10.0.0 - - '@oozcitak/util@10.0.0': {} - '@opentelemetry/api-logs@0.208.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -7411,130 +5276,6 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) - '@oxc-minify/binding-android-arm-eabi@0.112.0': - optional: true - - '@oxc-minify/binding-android-arm64@0.112.0': - optional: true - - '@oxc-minify/binding-darwin-arm64@0.112.0': - optional: true - - '@oxc-minify/binding-darwin-x64@0.112.0': - optional: true - - '@oxc-minify/binding-freebsd-x64@0.112.0': - optional: true - - '@oxc-minify/binding-linux-arm-gnueabihf@0.112.0': - optional: true - - '@oxc-minify/binding-linux-arm-musleabihf@0.112.0': - optional: true - - '@oxc-minify/binding-linux-arm64-gnu@0.112.0': - optional: true - - '@oxc-minify/binding-linux-arm64-musl@0.112.0': - optional: true - - '@oxc-minify/binding-linux-ppc64-gnu@0.112.0': - optional: true - - '@oxc-minify/binding-linux-riscv64-gnu@0.112.0': - optional: true - - '@oxc-minify/binding-linux-riscv64-musl@0.112.0': - optional: true - - '@oxc-minify/binding-linux-s390x-gnu@0.112.0': - optional: true - - '@oxc-minify/binding-linux-x64-gnu@0.112.0': - optional: true - - '@oxc-minify/binding-linux-x64-musl@0.112.0': - optional: true - - '@oxc-minify/binding-openharmony-arm64@0.112.0': - optional: true - - '@oxc-minify/binding-wasm32-wasi@0.112.0': - dependencies: - '@napi-rs/wasm-runtime': 1.1.1 - optional: true - - '@oxc-minify/binding-win32-arm64-msvc@0.112.0': - optional: true - - '@oxc-minify/binding-win32-ia32-msvc@0.112.0': - optional: true - - '@oxc-minify/binding-win32-x64-msvc@0.112.0': - optional: true - - '@oxc-transform/binding-android-arm-eabi@0.112.0': - optional: true - - '@oxc-transform/binding-android-arm64@0.112.0': - optional: true - - '@oxc-transform/binding-darwin-arm64@0.112.0': - optional: true - - '@oxc-transform/binding-darwin-x64@0.112.0': - optional: true - - '@oxc-transform/binding-freebsd-x64@0.112.0': - optional: true - - '@oxc-transform/binding-linux-arm-gnueabihf@0.112.0': - optional: true - - '@oxc-transform/binding-linux-arm-musleabihf@0.112.0': - optional: true - - '@oxc-transform/binding-linux-arm64-gnu@0.112.0': - optional: true - - '@oxc-transform/binding-linux-arm64-musl@0.112.0': - optional: true - - '@oxc-transform/binding-linux-ppc64-gnu@0.112.0': - optional: true - - '@oxc-transform/binding-linux-riscv64-gnu@0.112.0': - optional: true - - '@oxc-transform/binding-linux-riscv64-musl@0.112.0': - optional: true - - '@oxc-transform/binding-linux-s390x-gnu@0.112.0': - optional: true - - '@oxc-transform/binding-linux-x64-gnu@0.112.0': - optional: true - - '@oxc-transform/binding-linux-x64-musl@0.112.0': - optional: true - - '@oxc-transform/binding-openharmony-arm64@0.112.0': - optional: true - - '@oxc-transform/binding-wasm32-wasi@0.112.0': - dependencies: - '@napi-rs/wasm-runtime': 1.1.1 - optional: true - - '@oxc-transform/binding-win32-arm64-msvc@0.112.0': - optional: true - - '@oxc-transform/binding-win32-ia32-msvc@0.112.0': - optional: true - - '@oxc-transform/binding-win32-x64-msvc@0.112.0': - optional: true - '@pkgjs/parseargs@0.11.0': optional: true @@ -7582,22 +5323,21 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-arrow@1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-checkbox@1.3.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.5(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -7605,31 +5345,17 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collection@1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.2.3(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -7637,24 +5363,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.10)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-context@1.1.2(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-context@1.1.2(@types/react@19.2.10)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-context@1.1.3(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 @@ -7667,24 +5381,17 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-direction@1.1.1(@types/react@19.2.10)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -7692,16 +5399,15 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-focus-scope@1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/react-id@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -7710,38 +5416,21 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-id@1.1.1(@types/react@19.2.10)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - - '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-label@2.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popper@1.2.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -7751,19 +5440,17 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-portal@1.1.9(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-presence@1.1.5(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -7771,109 +5458,59 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.4(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.2.4(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-progress@1.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-context': 1.1.3(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-select@2.2.6(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-direction': 1.1.1(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.1(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-popper': 1.2.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.2.3(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-remove-scroll: 2.7.2(@types/react@18.3.27)(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/react-slot@1.2.3(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -7882,13 +5519,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-slot@1.2.3(@types/react@19.2.10)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-slot@1.2.4(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) @@ -7896,41 +5526,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-slot@1.2.4(@types/react@19.2.10)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.10)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.27)(react@18.3.1) @@ -7939,14 +5540,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.10)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -7954,13 +5547,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.10)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.10)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -7974,12 +5560,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.10)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.10 - '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 @@ -8000,14 +5580,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/rect@1.1.1': {} @@ -8026,10 +5605,6 @@ snapshots: '@react-google-maps/marker-clusterer@2.20.0': {} - '@rolldown/pluginutils@1.0.0-beta.40': {} - - '@rolldown/pluginutils@1.0.0-rc.2': {} - '@rollup/plugin-commonjs@28.0.1(rollup@4.55.1)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.55.1) @@ -8325,40 +5900,6 @@ snapshots: - encoding - supports-color - '@solid-primitives/event-listener@2.4.3(solid-js@1.9.11)': - dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 - - '@solid-primitives/keyboard@1.3.3(solid-js@1.9.11)': - dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) - '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 - - '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.11)': - dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) - '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) - '@solid-primitives/static-store': 0.1.2(solid-js@1.9.11) - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 - - '@solid-primitives/rootless@1.5.2(solid-js@1.9.11)': - dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 - - '@solid-primitives/static-store@0.1.2(solid-js@1.9.11)': - dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 - - '@solid-primitives/utils@6.3.2(solid-js@1.9.11)': - dependencies: - solid-js: 1.9.11 - '@standard-schema/utils@0.3.0': {} '@stomp/stompjs@7.2.1': {} @@ -8463,154 +6004,10 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.8.1 - '@tailwindcss/node@4.1.18': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.18 - - '@tailwindcss/oxide-android-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide@4.1.18': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))': - dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - - '@tanstack/devtools-client@0.0.3': - dependencies: - '@tanstack/devtools-event-client': 0.3.5 - - '@tanstack/devtools-client@0.0.5': - dependencies: - '@tanstack/devtools-event-client': 0.4.0 - - '@tanstack/devtools-event-bus@0.3.3': - dependencies: - ws: 8.19.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@tanstack/devtools-event-client@0.3.5': {} - - '@tanstack/devtools-event-client@0.4.0': {} - - '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.11)': - dependencies: - clsx: 2.1.1 - goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 - transitivePeerDependencies: - - csstype - - '@tanstack/devtools-vite@0.3.12(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))': - dependencies: - '@babel/core': 7.28.6 - '@babel/generator': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - '@tanstack/devtools-client': 0.0.5 - '@tanstack/devtools-event-bus': 0.3.3 - chalk: 5.6.2 - launch-editor: 2.12.0 - picomatch: 4.0.3 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@tanstack/devtools@0.7.0(csstype@3.2.3)(solid-js@1.9.11)': - dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) - '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.11) - '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.11) - '@tanstack/devtools-client': 0.0.3 - '@tanstack/devtools-event-bus': 0.3.3 - '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.11) - clsx: 2.1.1 - goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 - transitivePeerDependencies: - - bufferutil - - csstype - - utf-8-validate - - '@tanstack/history@1.154.14': {} - '@tanstack/query-core@5.90.19': {} '@tanstack/query-devtools@5.92.0': {} - '@tanstack/react-devtools@0.7.11(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)': - dependencies: - '@tanstack/devtools': 0.7.0(csstype@3.2.3)(solid-js@1.9.11) - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - transitivePeerDependencies: - - bufferutil - - csstype - - solid-js - - utf-8-validate - '@tanstack/react-query-devtools@5.91.2(@tanstack/react-query@5.90.19(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/query-devtools': 5.92.0 @@ -8622,306 +6019,29 @@ snapshots: '@tanstack/query-core': 5.90.19 react: 18.3.1 - '@tanstack/react-query@5.90.19(react@19.2.4)': - dependencies: - '@tanstack/query-core': 5.90.19 - react: 19.2.4 - - '@tanstack/react-router-devtools@1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.0)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/react-router': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-devtools-core': 1.158.0(@tanstack/router-core@1.158.0)(csstype@3.2.3) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@tanstack/router-core': 1.158.0 - transitivePeerDependencies: - - csstype - - '@tanstack/react-router-ssr-query@1.158.0(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.4))(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/query-core': 5.90.19 - '@tanstack/react-query': 5.90.19(react@19.2.4) - '@tanstack/react-router': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-ssr-query-core': 1.158.0(@tanstack/query-core@5.90.19)(@tanstack/router-core@1.158.0) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - transitivePeerDependencies: - - '@tanstack/router-core' - - '@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/history': 1.154.14 - '@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-core': 1.158.0 - isbot: 5.1.34 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - '@tanstack/react-start-client@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/react-router': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-core': 1.158.0 - '@tanstack/start-client-core': 1.158.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - '@tanstack/react-start-server@1.158.0(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/history': 1.154.14 - '@tanstack/react-router': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-core': 1.158.0 - '@tanstack/start-client-core': 1.158.0 - '@tanstack/start-server-core': 1.158.0(crossws@0.4.4(srvx@0.10.1)) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - transitivePeerDependencies: - - crossws - - '@tanstack/react-start@1.158.0(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1)': - dependencies: - '@tanstack/react-router': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-start-client': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/react-start-server': 1.158.0(crossws@0.4.4(srvx@0.10.1))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tanstack/router-utils': 1.158.0 - '@tanstack/start-client-core': 1.158.0 - '@tanstack/start-plugin-core': 1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.10.1))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1) - '@tanstack/start-server-core': 1.158.0(crossws@0.4.4(srvx@0.10.1)) - pathe: 2.0.3 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - transitivePeerDependencies: - - '@rsbuild/core' - - crossws - - supports-color - - vite-plugin-solid - - webpack - - '@tanstack/react-store@0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@tanstack/store': 0.8.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - use-sync-external-store: 1.6.0(react@19.2.4) - '@tanstack/react-virtual@3.13.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/virtual-core': 3.13.18 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@tanstack/router-core@1.158.0': - dependencies: - '@tanstack/history': 1.154.14 - '@tanstack/store': 0.8.0 - cookie-es: 2.0.0 - seroval: 1.5.0 - seroval-plugins: 1.5.0(seroval@1.5.0) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - '@tanstack/router-devtools-core@1.158.0(@tanstack/router-core@1.158.0)(csstype@3.2.3)': - dependencies: - '@tanstack/router-core': 1.158.0 - clsx: 2.1.1 - goober: 2.1.18(csstype@3.2.3) - tiny-invariant: 1.3.3 - optionalDependencies: - csstype: 3.2.3 - - '@tanstack/router-generator@1.158.0': - dependencies: - '@tanstack/router-core': 1.158.0 - '@tanstack/router-utils': 1.158.0 - '@tanstack/virtual-file-routes': 1.154.7 - prettier: 3.8.1 - recast: 0.23.11 - source-map: 0.7.6 - tsx: 4.21.0 - zod: 3.25.76 - transitivePeerDependencies: - - supports-color - - '@tanstack/router-plugin@1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1)': - dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) - '@babel/template': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - '@tanstack/router-core': 1.158.0 - '@tanstack/router-generator': 1.158.0 - '@tanstack/router-utils': 1.158.0 - '@tanstack/virtual-file-routes': 1.154.7 - chokidar: 3.6.0 - unplugin: 2.3.11 - zod: 3.25.76 - optionalDependencies: - '@tanstack/react-router': 1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - webpack: 5.104.1 - transitivePeerDependencies: - - supports-color - - '@tanstack/router-ssr-query-core@1.158.0(@tanstack/query-core@5.90.19)(@tanstack/router-core@1.158.0)': - dependencies: - '@tanstack/query-core': 5.90.19 - '@tanstack/router-core': 1.158.0 - - '@tanstack/router-utils@1.158.0': - dependencies: - '@babel/core': 7.28.6 - '@babel/generator': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - ansis: 4.2.0 - babel-dead-code-elimination: 1.0.12 - diff: 8.0.3 - pathe: 2.0.3 - tinyglobby: 0.2.15 - transitivePeerDependencies: - - supports-color - - '@tanstack/start-client-core@1.158.0': - dependencies: - '@tanstack/router-core': 1.158.0 - '@tanstack/start-fn-stubs': 1.154.7 - '@tanstack/start-storage-context': 1.158.0 - seroval: 1.5.0 - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - '@tanstack/start-fn-stubs@1.154.7': {} - - '@tanstack/start-plugin-core@1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.10.1))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1)': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/core': 7.28.6 - '@babel/types': 7.28.6 - '@rolldown/pluginutils': 1.0.0-beta.40 - '@tanstack/router-core': 1.158.0 - '@tanstack/router-generator': 1.158.0 - '@tanstack/router-plugin': 1.158.0(@tanstack/react-router@1.158.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))(webpack@5.104.1) - '@tanstack/router-utils': 1.158.0 - '@tanstack/start-client-core': 1.158.0 - '@tanstack/start-server-core': 1.158.0(crossws@0.4.4(srvx@0.10.1)) - cheerio: 1.2.0 - exsolve: 1.0.8 - pathe: 2.0.3 - srvx: 0.10.1 - tinyglobby: 0.2.15 - ufo: 1.6.3 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - vitefu: 1.1.1(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - xmlbuilder2: 4.0.3 - zod: 3.25.76 - transitivePeerDependencies: - - '@rsbuild/core' - - '@tanstack/react-router' - - crossws - - supports-color - - vite-plugin-solid - - webpack - - '@tanstack/start-server-core@1.158.0(crossws@0.4.4(srvx@0.10.1))': - dependencies: - '@tanstack/history': 1.154.14 - '@tanstack/router-core': 1.158.0 - '@tanstack/start-client-core': 1.158.0 - '@tanstack/start-storage-context': 1.158.0 - h3-v2: h3@2.0.1-rc.11(crossws@0.4.4(srvx@0.10.1)) - seroval: 1.5.0 - tiny-invariant: 1.3.3 - transitivePeerDependencies: - - crossws - - '@tanstack/start-storage-context@1.158.0': - dependencies: - '@tanstack/router-core': 1.158.0 - - '@tanstack/store@0.8.0': {} - '@tanstack/virtual-core@3.13.18': {} - '@tanstack/virtual-file-routes@1.154.7': {} - - '@testing-library/dom@10.4.1': - dependencies: - '@babel/code-frame': 7.28.6 - '@babel/runtime': 7.28.6 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 - - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/runtime': 7.28.6 - '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.10 - '@types/react-dom': 19.2.3(@types/react@19.2.10) - '@tootallnate/once@2.0.0': optional: true '@trysound/sax@0.2.0': {} - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/aria-query@5.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.6 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.6 - '@types/caseless@0.12.5': optional: true - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - '@types/connect@3.4.38': dependencies: - '@types/node': 22.19.7 + '@types/node': 20.19.30 '@types/conventional-commits-parser@5.0.2': dependencies: - '@types/node': 22.19.7 - - '@types/deep-eql@4.0.2': {} + '@types/node': 20.19.30 '@types/eslint-scope@3.7.7': dependencies: @@ -8942,7 +6062,7 @@ snapshots: '@types/jsonwebtoken@9.0.10': dependencies: '@types/ms': 2.1.0 - '@types/node': 22.19.7 + '@types/node': 20.19.30 '@types/long@4.0.2': optional: true @@ -8951,7 +6071,7 @@ snapshots: '@types/mysql@2.15.27': dependencies: - '@types/node': 22.19.7 + '@types/node': 20.19.30 '@types/node@20.19.30': dependencies: @@ -8967,103 +6087,32 @@ snapshots: '@types/pg@8.15.6': dependencies: - '@types/node': 22.19.7 + '@types/node': 20.19.30 pg-protocol: 1.11.0 pg-types: 2.2.0 '@types/prop-types@15.7.15': {} - '@types/react-dom@18.3.7(@types/react@18.3.27)': - dependencies: - '@types/react': 18.3.27 - - '@types/react-dom@19.2.3(@types/react@19.2.10)': - dependencies: - '@types/react': 19.2.10 - '@types/react@18.3.27': dependencies: '@types/prop-types': 15.7.15 csstype: 3.2.3 - '@types/react@19.2.10': - dependencies: - csstype: 3.2.3 - '@types/request@2.48.13': dependencies: '@types/caseless': 0.12.5 - '@types/node': 22.19.7 + '@types/node': 20.19.30 '@types/tough-cookie': 4.0.5 form-data: 2.5.5 optional: true '@types/tedious@4.0.14': dependencies: - '@types/node': 22.19.7 + '@types/node': 20.19.30 '@types/tough-cookie@4.0.5': optional: true - '@vercel/speed-insights@1.3.1(next@14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': - optionalDependencies: - next: 14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - - '@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-rc.2 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@3.2.4': - dependencies: - '@types/chai': 5.2.3 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - tinyrainbow: 2.0.0 - - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - - '@vitest/pretty-format@3.2.4': - dependencies: - tinyrainbow: 2.0.0 - - '@vitest/runner@3.2.4': - dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.1.0 - - '@vitest/snapshot@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.4 - - '@vitest/utils@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -9170,7 +6219,8 @@ snapshots: transitivePeerDependencies: - supports-color - agent-base@7.1.4: {} + agent-base@7.1.4: + optional: true ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: @@ -9196,12 +6246,8 @@ snapshots: dependencies: color-convert: 2.0.1 - ansi-styles@5.2.0: {} - ansi-styles@6.2.3: {} - ansis@4.2.0: {} - any-promise@1.3.0: {} anymatch@3.1.3: @@ -9217,21 +6263,11 @@ snapshots: dependencies: tslib: 2.8.1 - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - array-ify@1.0.0: {} arrify@2.0.1: optional: true - assertion-error@2.0.1: {} - - ast-types@0.16.1: - dependencies: - tslib: 2.8.1 - async-retry@1.3.3: dependencies: retry: 0.13.1 @@ -9256,15 +6292,6 @@ snapshots: transitivePeerDependencies: - debug - babel-dead-code-elimination@1.0.12: - dependencies: - '@babel/core': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - transitivePeerDependencies: - - supports-color - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.6): dependencies: '@babel/compat-data': 7.28.6 @@ -9296,10 +6323,6 @@ snapshots: baseline-browser-mapping@2.9.15: {} - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - bignumber.js@9.3.1: optional: true @@ -9331,8 +6354,6 @@ snapshots: dependencies: streamsearch: 1.1.0 - cac@6.7.14: {} - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -9346,14 +6367,6 @@ snapshots: caniuse-lite@1.0.30001764: {} - chai@5.3.3: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.3 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -9361,31 +6374,6 @@ snapshots: chalk@5.6.2: {} - check-error@2.1.3: {} - - cheerio-select@2.1.0: - dependencies: - boolbase: 1.0.0 - css-select: 5.2.2 - css-what: 6.2.2 - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - - cheerio@1.2.0: - dependencies: - cheerio-select: 2.1.0 - dom-serializer: 2.0.0 - domhandler: 5.0.3 - domutils: 3.2.2 - encoding-sniffer: 0.2.1 - htmlparser2: 10.1.0 - parse5: 7.3.0 - parse5-htmlparser2-tree-adapter: 7.1.0 - parse5-parser-stream: 7.1.2 - undici: 7.20.0 - whatwg-mimetype: 4.0.0 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -9426,6 +6414,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@11.1.0: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -9439,8 +6429,6 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 - consola@3.4.2: {} - conventional-changelog-angular@7.0.0: dependencies: compare-func: 2.0.0 @@ -9458,8 +6446,6 @@ snapshots: convert-source-map@2.0.0: {} - cookie-es@2.0.0: {} - core-js-compat@3.47.0: dependencies: browserslist: 4.28.1 @@ -9505,10 +6491,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crossws@0.4.4(srvx@0.10.1): - optionalDependencies: - srvx: 0.10.1 - css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -9522,14 +6504,9 @@ snapshots: mdn-data: 2.0.28 source-map-js: 1.2.1 - css-tree@2.3.1: - dependencies: - mdn-data: 2.0.30 - source-map-js: 1.2.1 - - css-tree@3.1.0: + css-tree@2.3.1: dependencies: - mdn-data: 2.12.2 + mdn-data: 2.0.30 source-map-js: 1.2.1 css-what@6.2.2: {} @@ -9540,26 +6517,10 @@ snapshots: dependencies: css-tree: 2.2.1 - cssstyle@5.3.7: - dependencies: - '@asamuzakjp/css-color': 4.1.1 - '@csstools/css-syntax-patches-for-csstree': 1.0.26 - css-tree: 3.1.0 - lru-cache: 11.2.5 - csstype@3.2.3: {} dargs@8.1.0: {} - data-urls@6.0.1: - dependencies: - whatwg-mimetype: 5.0.0 - whatwg-url: 15.1.0 - - date-fns@4.1.0: {} - - db0@0.3.4: {} - debug@3.2.7: dependencies: ms: 2.1.3 @@ -9568,28 +6529,16 @@ snapshots: dependencies: ms: 2.1.3 - decimal.js@10.6.0: {} - - deep-eql@5.0.2: {} - deepmerge@4.3.1: {} delayed-stream@1.0.0: {} - dequal@2.0.3: {} - - detect-libc@2.1.2: {} - detect-node-es@1.1.0: {} didyoumean@1.2.2: {} - diff@8.0.3: {} - dlv@1.1.3: {} - dom-accessibility-api@0.5.16: {} - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -9645,11 +6594,6 @@ snapshots: emoji-regex@9.2.2: {} - encoding-sniffer@0.2.1: - dependencies: - iconv-lite: 0.6.3 - whatwg-encoding: 3.1.1 - end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -9662,10 +6606,6 @@ snapshots: entities@4.5.0: {} - entities@6.0.1: {} - - entities@7.0.1: {} - env-paths@2.2.1: {} error-ex@1.3.4: @@ -9676,8 +6616,6 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} - es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: @@ -9691,35 +6629,6 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.27.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.2 - '@esbuild/android-arm': 0.27.2 - '@esbuild/android-arm64': 0.27.2 - '@esbuild/android-x64': 0.27.2 - '@esbuild/darwin-arm64': 0.27.2 - '@esbuild/darwin-x64': 0.27.2 - '@esbuild/freebsd-arm64': 0.27.2 - '@esbuild/freebsd-x64': 0.27.2 - '@esbuild/linux-arm': 0.27.2 - '@esbuild/linux-arm64': 0.27.2 - '@esbuild/linux-ia32': 0.27.2 - '@esbuild/linux-loong64': 0.27.2 - '@esbuild/linux-mips64el': 0.27.2 - '@esbuild/linux-ppc64': 0.27.2 - '@esbuild/linux-riscv64': 0.27.2 - '@esbuild/linux-s390x': 0.27.2 - '@esbuild/linux-x64': 0.27.2 - '@esbuild/netbsd-arm64': 0.27.2 - '@esbuild/netbsd-x64': 0.27.2 - '@esbuild/openbsd-arm64': 0.27.2 - '@esbuild/openbsd-x64': 0.27.2 - '@esbuild/openharmony-arm64': 0.27.2 - '@esbuild/sunos-x64': 0.27.2 - '@esbuild/win32-arm64': 0.27.2 - '@esbuild/win32-ia32': 0.27.2 - '@esbuild/win32-x64': 0.27.2 - escalade@3.2.0: {} eslint-scope@5.1.1: @@ -9727,8 +6636,6 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 - esprima@4.0.1: {} - esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -9739,10 +6646,6 @@ snapshots: estree-walker@2.0.2: {} - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - esutils@2.0.3: {} event-target-shim@5.0.1: @@ -9752,10 +6655,6 @@ snapshots: eventsource@2.0.2: {} - expect-type@1.3.0: {} - - exsolve@1.0.8: {} - extend@3.0.2: optional: true @@ -9906,10 +6805,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-tsconfig@4.13.1: - dependencies: - resolve-pkg-maps: 1.0.0 - git-raw-commits@4.0.0: dependencies: dargs: 8.1.0 @@ -9939,12 +6834,6 @@ snapshots: dependencies: ini: 4.1.1 - globrex@0.1.2: {} - - goober@2.1.18(csstype@3.2.3): - dependencies: - csstype: 3.2.3 - google-auth-library@9.15.1: dependencies: base64-js: 1.5.1 @@ -9993,13 +6882,6 @@ snapshots: - supports-color optional: true - h3@2.0.1-rc.11(crossws@0.4.4(srvx@0.10.1)): - dependencies: - rou3: 0.7.12 - srvx: 0.10.1 - optionalDependencies: - crossws: 0.4.4(srvx@0.10.1) - has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -10012,22 +6894,9 @@ snapshots: dependencies: function-bind: 1.1.2 - html-encoding-sniffer@6.0.0: - dependencies: - '@exodus/bytes': 1.11.0 - transitivePeerDependencies: - - '@noble/hashes' - html-entities@2.6.0: optional: true - htmlparser2@10.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 7.0.1 - htmlparser2@8.0.2: dependencies: domelementtype: 2.3.0 @@ -10046,13 +6915,6 @@ snapshots: - supports-color optional: true - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -10066,13 +6928,10 @@ snapshots: debug: 4.4.3 transitivePeerDependencies: - supports-color + optional: true husky@9.1.7: {} - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -10117,8 +6976,6 @@ snapshots: is-obj@2.0.0: {} - is-potential-custom-element-name@1.0.1: {} - is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -10130,8 +6987,6 @@ snapshots: dependencies: text-extensions: 2.4.0 - isbot@5.1.34: {} - isexe@2.0.0: {} jackspeak@3.4.3: @@ -10142,7 +6997,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 22.19.7 + '@types/node': 20.19.30 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -10154,40 +7009,10 @@ snapshots: js-tokens@4.0.0: {} - js-tokens@9.0.1: {} - js-yaml@4.1.1: dependencies: argparse: 2.0.1 - jsdom@27.4.0: - dependencies: - '@acemir/cssom': 0.9.31 - '@asamuzakjp/dom-selector': 6.7.7 - '@exodus/bytes': 1.11.0 - cssstyle: 5.3.7 - data-urls: 6.0.1 - decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.0 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.19.0 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - '@noble/hashes' - - bufferutil - - supports-color - - utf-8-validate - jsesc@3.1.0: {} json-bigint@1.0.0: @@ -10239,60 +7064,6 @@ snapshots: kdbush@4.0.2: {} - launch-editor@2.12.0: - dependencies: - picocolors: 1.1.1 - shell-quote: 1.8.3 - - lightningcss-android-arm64@1.30.2: - optional: true - - lightningcss-darwin-arm64@1.30.2: - optional: true - - lightningcss-darwin-x64@1.30.2: - optional: true - - lightningcss-freebsd-x64@1.30.2: - optional: true - - lightningcss-linux-arm-gnueabihf@1.30.2: - optional: true - - lightningcss-linux-arm64-gnu@1.30.2: - optional: true - - lightningcss-linux-arm64-musl@1.30.2: - optional: true - - lightningcss-linux-x64-gnu@1.30.2: - optional: true - - lightningcss-linux-x64-musl@1.30.2: - optional: true - - lightningcss-win32-arm64-msvc@1.30.2: - optional: true - - lightningcss-win32-x64-msvc@1.30.2: - optional: true - - lightningcss@1.30.2: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - lilconfig@3.1.3: {} limiter@1.1.5: {} @@ -10357,16 +7128,12 @@ snapshots: dependencies: js-tokens: 4.0.0 - loupe@3.2.1: {} - lower-case@2.0.2: dependencies: tslib: 2.8.1 lru-cache@10.4.3: {} - lru-cache@11.2.5: {} - lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -10384,12 +7151,6 @@ snapshots: dependencies: react: 18.3.1 - lucide-react@0.561.0(react@19.2.4): - dependencies: - react: 19.2.4 - - lz-string@1.5.0: {} - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -10404,8 +7165,6 @@ snapshots: mdn-data@2.0.30: {} - mdn-data@2.12.2: {} - meow@12.1.1: {} merge-stream@2.0.0: {} @@ -10482,56 +7241,6 @@ snapshots: - '@babel/core' - babel-plugin-macros - nf3@0.3.7: {} - - nitro-nightly@3.0.1-20260202-124820-1954b824(chokidar@3.6.0)(lru-cache@11.2.5)(rollup@4.55.1)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)): - dependencies: - consola: 3.4.2 - crossws: 0.4.4(srvx@0.10.1) - db0: 0.3.4 - h3: 2.0.1-rc.11(crossws@0.4.4(srvx@0.10.1)) - jiti: 2.6.1 - nf3: 0.3.7 - ofetch: 2.0.0-alpha.3 - ohash: 2.0.11 - oxc-minify: 0.112.0 - oxc-transform: 0.112.0 - srvx: 0.10.1 - undici: 7.20.0 - unenv: 2.0.0-rc.24 - unstorage: 2.0.0-alpha.5(chokidar@3.6.0)(db0@0.3.4)(lru-cache@11.2.5)(ofetch@2.0.0-alpha.3) - optionalDependencies: - rollup: 4.55.1 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@libsql/client' - - '@netlify/blobs' - - '@planetscale/database' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - better-sqlite3 - - chokidar - - drizzle-orm - - idb-keyval - - ioredis - - lru-cache - - mongodb - - mysql2 - - sqlite3 - - uploadthing - no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -10555,61 +7264,11 @@ snapshots: object-hash@3.0.0: {} - ofetch@2.0.0-alpha.3: {} - - ohash@2.0.11: {} - once@1.4.0: dependencies: wrappy: 1.0.2 optional: true - oxc-minify@0.112.0: - optionalDependencies: - '@oxc-minify/binding-android-arm-eabi': 0.112.0 - '@oxc-minify/binding-android-arm64': 0.112.0 - '@oxc-minify/binding-darwin-arm64': 0.112.0 - '@oxc-minify/binding-darwin-x64': 0.112.0 - '@oxc-minify/binding-freebsd-x64': 0.112.0 - '@oxc-minify/binding-linux-arm-gnueabihf': 0.112.0 - '@oxc-minify/binding-linux-arm-musleabihf': 0.112.0 - '@oxc-minify/binding-linux-arm64-gnu': 0.112.0 - '@oxc-minify/binding-linux-arm64-musl': 0.112.0 - '@oxc-minify/binding-linux-ppc64-gnu': 0.112.0 - '@oxc-minify/binding-linux-riscv64-gnu': 0.112.0 - '@oxc-minify/binding-linux-riscv64-musl': 0.112.0 - '@oxc-minify/binding-linux-s390x-gnu': 0.112.0 - '@oxc-minify/binding-linux-x64-gnu': 0.112.0 - '@oxc-minify/binding-linux-x64-musl': 0.112.0 - '@oxc-minify/binding-openharmony-arm64': 0.112.0 - '@oxc-minify/binding-wasm32-wasi': 0.112.0 - '@oxc-minify/binding-win32-arm64-msvc': 0.112.0 - '@oxc-minify/binding-win32-ia32-msvc': 0.112.0 - '@oxc-minify/binding-win32-x64-msvc': 0.112.0 - - oxc-transform@0.112.0: - optionalDependencies: - '@oxc-transform/binding-android-arm-eabi': 0.112.0 - '@oxc-transform/binding-android-arm64': 0.112.0 - '@oxc-transform/binding-darwin-arm64': 0.112.0 - '@oxc-transform/binding-darwin-x64': 0.112.0 - '@oxc-transform/binding-freebsd-x64': 0.112.0 - '@oxc-transform/binding-linux-arm-gnueabihf': 0.112.0 - '@oxc-transform/binding-linux-arm-musleabihf': 0.112.0 - '@oxc-transform/binding-linux-arm64-gnu': 0.112.0 - '@oxc-transform/binding-linux-arm64-musl': 0.112.0 - '@oxc-transform/binding-linux-ppc64-gnu': 0.112.0 - '@oxc-transform/binding-linux-riscv64-gnu': 0.112.0 - '@oxc-transform/binding-linux-riscv64-musl': 0.112.0 - '@oxc-transform/binding-linux-s390x-gnu': 0.112.0 - '@oxc-transform/binding-linux-x64-gnu': 0.112.0 - '@oxc-transform/binding-linux-x64-musl': 0.112.0 - '@oxc-transform/binding-openharmony-arm64': 0.112.0 - '@oxc-transform/binding-wasm32-wasi': 0.112.0 - '@oxc-transform/binding-win32-arm64-msvc': 0.112.0 - '@oxc-transform/binding-win32-ia32-msvc': 0.112.0 - '@oxc-transform/binding-win32-x64-msvc': 0.112.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -10639,23 +7298,6 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse5-htmlparser2-tree-adapter@7.1.0: - dependencies: - domhandler: 5.0.3 - parse5: 7.3.0 - - parse5-parser-stream@7.1.2: - dependencies: - parse5: 7.3.0 - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - parse5@8.0.0: - dependencies: - entities: 6.0.1 - path-exists@4.0.0: {} path-exists@5.0.0: {} @@ -10671,10 +7313,6 @@ snapshots: path-type@4.0.0: {} - pathe@2.0.3: {} - - pathval@2.0.1: {} - pg-int8@1.0.1: {} pg-protocol@1.11.0: {} @@ -10709,13 +7347,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.6 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.6 - tsx: 4.21.0 + yaml: 2.8.2 postcss-media-query-parser@0.2.3: {} @@ -10753,14 +7391,6 @@ snapshots: dependencies: xtend: 4.0.2 - prettier@3.8.1: {} - - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - progress@2.0.3: {} proto3-json-serializer@2.0.2: @@ -10780,14 +7410,12 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.19.7 + '@types/node': 20.19.30 long: 5.3.2 optional: true proxy-from-env@1.1.0: {} - punycode@2.3.1: {} - querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -10802,19 +7430,10 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-dom@19.2.4(react@19.2.4): - dependencies: - react: 19.2.4 - scheduler: 0.27.0 - react-hook-form@7.71.1(react@18.3.1): dependencies: react: 18.3.1 - react-is@17.0.2: {} - - react-refresh@0.18.0: {} - react-remove-scroll-bar@2.3.8(@types/react@18.3.27)(react@18.3.1): dependencies: react: 18.3.1 @@ -10846,8 +7465,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - react@19.2.4: {} - read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -10863,14 +7480,6 @@ snapshots: dependencies: picomatch: 2.3.1 - recast@0.23.11: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.8.1 - regenerate-unicode-properties@10.2.2: dependencies: regenerate: 1.4.2 @@ -10909,8 +7518,6 @@ snapshots: resolve-from@5.0.0: {} - resolve-pkg-maps@1.0.0: {} - resolve@1.22.11: dependencies: is-core-module: 2.16.1 @@ -10963,26 +7570,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 - rou3@0.7.12: {} - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 safe-buffer@5.2.1: {} - safer-buffer@2.1.2: {} - - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - scheduler@0.23.2: dependencies: loose-envify: 1.4.0 - scheduler@0.27.0: {} - schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 @@ -10998,22 +7595,12 @@ snapshots: dependencies: randombytes: 2.1.0 - seroval-plugins@1.5.0(seroval@1.5.0): - dependencies: - seroval: 1.5.0 - - seroval@1.5.0: {} - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} - shell-quote@1.8.3: {} - - siginfo@2.0.0: {} - signal-exit@4.1.0: {} snake-case@3.0.4: @@ -11031,17 +7618,6 @@ snapshots: transitivePeerDependencies: - supports-color - solid-js@1.9.11: - dependencies: - csstype: 3.2.3 - seroval: 1.5.0 - seroval-plugins: 1.5.0(seroval@1.5.0) - - sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -11051,20 +7627,12 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.6: {} - split2@4.2.0: {} - srvx@0.10.1: {} - - stackback@0.0.2: {} - stacktrace-parser@0.1.11: dependencies: type-fest: 0.7.1 - std-env@3.10.0: {} - stream-events@1.0.5: dependencies: stubs: 3.0.0 @@ -11100,10 +7668,6 @@ snapshots: dependencies: ansi-regex: 6.2.2 - strip-literal@3.1.0: - dependencies: - js-tokens: 9.0.1 - strnum@1.1.2: optional: true @@ -11153,15 +7717,13 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 - symbol-tree@3.2.4: {} - tailwind-merge@3.4.0: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.21.0)): + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(yaml@2.8.2)): dependencies: - tailwindcss: 3.4.19(tsx@4.21.0) + tailwindcss: 3.4.19(yaml@2.8.2) - tailwindcss@3.4.19(tsx@4.21.0): + tailwindcss@3.4.19(yaml@2.8.2): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -11180,7 +7742,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -11189,8 +7751,6 @@ snapshots: - tsx - yaml - tailwindcss@4.1.18: {} - tapable@2.3.0: {} teeny-request@9.0.0: @@ -11235,14 +7795,6 @@ snapshots: through@2.3.8: {} - tiny-invariant@1.3.3: {} - - tiny-warning@1.0.3: {} - - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -11250,47 +7802,16 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.4: {} - - tldts-core@7.0.21: {} - - tldts@7.0.21: - dependencies: - tldts-core: 7.0.21 - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - tough-cookie@6.0.0: - dependencies: - tldts: 7.0.21 - tr46@0.0.3: {} - tr46@6.0.0: - dependencies: - punycode: 2.3.1 - ts-interface-checker@0.1.13: {} - tsconfck@3.1.6(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 - tslib@2.8.1: {} - tsx@4.21.0: - dependencies: - esbuild: 0.27.2 - get-tsconfig: 4.13.1 - optionalDependencies: - fsevents: 2.3.3 - turbo-darwin-64@2.7.5: optional: true @@ -11322,16 +7843,8 @@ snapshots: typescript@5.9.3: {} - ufo@1.6.3: {} - undici-types@6.21.0: {} - undici@7.20.0: {} - - unenv@2.0.0-rc.24: - dependencies: - pathe: 2.0.3 - unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -11352,20 +7865,6 @@ snapshots: webpack-sources: 3.3.3 webpack-virtual-modules: 0.5.0 - unplugin@2.3.11: - dependencies: - '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 - picomatch: 4.0.3 - webpack-virtual-modules: 0.6.2 - - unstorage@2.0.0-alpha.5(chokidar@3.6.0)(db0@0.3.4)(lru-cache@11.2.5)(ofetch@2.0.0-alpha.3): - optionalDependencies: - chokidar: 3.6.0 - db0: 0.3.4 - lru-cache: 11.2.5 - ofetch: 2.0.0-alpha.3 - update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -11392,15 +7891,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - use-sync-external-store@1.6.0(react@18.3.1): - dependencies: - react: 18.3.1 - optional: true - - use-sync-external-store@1.6.0(react@19.2.4): - dependencies: - react: 19.2.4 - util-deprecate@1.0.2: {} uuid@10.0.0: {} @@ -11410,120 +7900,17 @@ snapshots: uuid@9.0.1: {} - vite-node@3.2.4(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0): - dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite-tsconfig-paths@6.0.5(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)): - dependencies: - debug: 4.4.3 - globrex: 0.1.2 - tsconfck: 3.1.6(typescript@5.9.3) - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - transitivePeerDependencies: - - supports-color - - typescript - - vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0): - dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.55.1 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.19.7 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - terser: 5.46.0 - tsx: 4.21.0 - - vitefu@1.1.1(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)): - optionalDependencies: - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - - vitest@3.2.4(@types/node@22.19.7)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3 - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - vite-node: 3.2.4(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 22.19.7 - jsdom: 27.4.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - web-vitals@5.1.0: {} - webidl-conversions@3.0.1: {} - webidl-conversions@8.0.1: {} - webpack-sources@3.3.3: {} webpack-virtual-modules@0.5.0: {} - webpack-virtual-modules@0.6.2: {} - webpack@5.104.1: dependencies: '@types/eslint-scope': 3.7.7 @@ -11564,19 +7951,6 @@ snapshots: websocket-extensions@0.1.4: {} - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@4.0.0: {} - - whatwg-mimetype@5.0.0: {} - - whatwg-url@15.1.0: - dependencies: - tr46: 6.0.0 - webidl-conversions: 8.0.1 - whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -11586,11 +7960,6 @@ snapshots: dependencies: isexe: 2.0.0 - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -11606,19 +7975,6 @@ snapshots: wrappy@1.0.2: optional: true - ws@8.19.0: {} - - xml-name-validator@5.0.0: {} - - xmlbuilder2@4.0.3: - dependencies: - '@oozcitak/dom': 2.0.2 - '@oozcitak/infra': 2.0.2 - '@oozcitak/util': 10.0.0 - js-yaml: 4.1.1 - - xmlchars@2.2.0: {} - xtend@4.0.2: {} y18n@5.0.8: {} @@ -11627,6 +7983,8 @@ snapshots: yallist@4.0.0: {} + yaml@2.8.2: {} + yargs-parser@21.1.1: {} yargs@17.7.2: @@ -11643,12 +8001,9 @@ snapshots: yocto-queue@1.2.2: {} - zod@3.25.76: {} - - zod@4.3.5: {} + zod@4.3.6: {} - zustand@5.0.10(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + zustand@5.0.10(@types/react@18.3.27)(react@18.3.1): optionalDependencies: '@types/react': 18.3.27 react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) From 897c7d0b21f60f0e343e7bf8acf4416414b9c2a1 Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 18:45:25 +0900 Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=94=A7=20bruno=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=20=EB=8F=99=EA=B8=B0=ED=99=94=20=EC=9B=90=EA=B2=A9=20fallback?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + docs/bruno-typescript-guide.md | 16 +++- docs/skills/univ-extends-bruno-sync-skill.md | 45 +++++++++++ packages/api-schema/package.json | 3 +- packages/api-schema/scripts/sync-bruno.mjs | 83 ++++++++++++++++++++ 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 docs/skills/univ-extends-bruno-sync-skill.md create mode 100644 packages/api-schema/scripts/sync-bruno.mjs diff --git a/.gitignore b/.gitignore index 45069428..4d9ac051 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ # generated api schema packages/api-schema/src/apis/ +packages/api-schema/.cache/ # misc .DS_Store diff --git a/docs/bruno-typescript-guide.md b/docs/bruno-typescript-guide.md index b1c5f2c1..e5fdd93a 100644 --- a/docs/bruno-typescript-guide.md +++ b/docs/bruno-typescript-guide.md @@ -13,16 +13,30 @@ # 스키마 동기화 (필요할 때 수동 실행) pnpm run sync:bruno +# 항상 원격 명세 저장소에서 동기화 +BRUNO_REPO_URL=https://github.com//.git pnpm --filter @solid-connect/api-schema run sync:bruno:remote + # 전체 빌드 시에도 자동으로 실행되도록 turbo에 연동 pnpm run build ``` ## 3) 스키마 생성 흐름 -1. Bruno 정의 위치: `api-docs/Solid Connection/**/*.bru` +1. Bruno 정의 위치(우선순위) + - `BRUNO_COLLECTION_DIR` 환경 변수 지정 경로 + - 로컬 기본 경로: `api-docs/Solid Connection/**/*.bru` + - 로컬 경로가 없을 때 원격 저장소(`BRUNO_REPO_URL`)를 clone 후 `BRUNO_COLLECTION_PATH` 하위 경로 2. 생성 명령: `bruno-api generate-hooks` 3. 생성 결과: `packages/api-schema/src/apis/**` +### 원격 동기화용 환경 변수 + +- `BRUNO_SOURCE_MODE`: `auto` | `local` | `remote` (기본값: `auto`) +- `BRUNO_COLLECTION_DIR`: 명세 폴더 절대/상대 경로 +- `BRUNO_REPO_URL`: 원격 Bruno 저장소 URL (`remote` 모드에서 필수) +- `BRUNO_REPO_REF`: 원격 브랜치/태그 (기본값: `main`) +- `BRUNO_COLLECTION_PATH`: 저장소 내부 컬렉션 경로 (기본값: `Solid Connection`) + ## 4) 파일/폴더 네이밍 규칙 `bruno-api-typescript`는 폴더/파일명 규칙에 따라 API 이름을 생성합니다. diff --git a/docs/skills/univ-extends-bruno-sync-skill.md b/docs/skills/univ-extends-bruno-sync-skill.md new file mode 100644 index 00000000..d983228e --- /dev/null +++ b/docs/skills/univ-extends-bruno-sync-skill.md @@ -0,0 +1,45 @@ +# Skill: feat/univ-extends 리베이스 + Bruno 명세 동기화 + +## 목적 + +- `feat/univ-extends`를 최신 기준 브랜치에 리베이스한다. +- Bruno 명세 변경이 생겨도 TypeScript API 코드를 재생성할 수 있는 구조를 유지한다. + +## 리베이스 절차 + +1. 기준 브랜치 fetch + - `git fetch --all --prune` +2. 기준 브랜치 확인 + - `develop`이 없으면 로컬 `develop`을 최신 `origin/main`으로 맞춘 뒤 사용 +3. 리베이스 실행 + - `git rebase develop` +4. 충돌 처리 원칙 + - 자동 생성 API 충돌은 의미 없는 대량 충돌이면 해당 커밋 `git rebase --skip` + - 기능 코드 충돌은 수동 병합 후 `git add` + `git rebase --continue` + +## Bruno 동기화 절차 + +1. 기본 실행 + - `pnpm run sync:bruno` +2. 원격 명세 강제 동기화 + - `BRUNO_REPO_URL= pnpm --filter @solid-connect/api-schema run sync:bruno:remote` +3. 모드 제어 + - `BRUNO_SOURCE_MODE=local|remote|auto` + +## 환경 변수 규칙 + +- `BRUNO_COLLECTION_DIR`: 로컬 명세 폴더를 직접 지정 +- `BRUNO_REPO_URL`: 원격 Bruno 저장소 URL +- `BRUNO_REPO_REF`: 원격 브랜치/태그 (기본 `main`) +- `BRUNO_COLLECTION_PATH`: 저장소 내부 명세 폴더 (기본 `Solid Connection`) + +## 검증 체크리스트 + +1. `pnpm --filter @solid-connect/api-schema run sync:bruno` +2. `pnpm typecheck` +3. `pnpm build` + +## 실패 대응 + +- 로컬 명세 폴더 미존재 + `BRUNO_REPO_URL` 미설정이면 즉시 실패한다. +- 원격 clone 성공 후 `BRUNO_COLLECTION_PATH` 경로가 없으면 즉시 실패한다. diff --git a/packages/api-schema/package.json b/packages/api-schema/package.json index 95b7928c..21f48415 100644 --- a/packages/api-schema/package.json +++ b/packages/api-schema/package.json @@ -3,7 +3,8 @@ "version": "0.0.0", "private": true, "scripts": { - "sync:bruno": "pnpm -C ../bruno-api-typescript run build && node ../bruno-api-typescript/dist/cli/index.js generate-hooks -i \"../../../api-docs/Solid Connection\" -o \"./src/apis\" --axios-path \"../axiosInstance\"", + "sync:bruno": "node ./scripts/sync-bruno.mjs", + "sync:bruno:remote": "BRUNO_SOURCE_MODE=remote node ./scripts/sync-bruno.mjs", "build": "pnpm run sync:bruno", "typecheck": "tsc --noEmit" }, diff --git a/packages/api-schema/scripts/sync-bruno.mjs b/packages/api-schema/scripts/sync-bruno.mjs new file mode 100644 index 00000000..a66ccf9f --- /dev/null +++ b/packages/api-schema/scripts/sync-bruno.mjs @@ -0,0 +1,83 @@ +import { spawnSync } from "node:child_process"; +import { existsSync, mkdirSync, rmSync } from "node:fs"; +import { resolve } from "node:path"; + +const rootDir = resolve(process.cwd()); +const defaultLocalCollectionDir = resolve(rootDir, "../../../api-docs/Solid Connection"); +const cacheRoot = resolve(rootDir, ".cache"); +const checkoutDir = resolve(cacheRoot, "bruno-source"); +const sourceMode = process.env.BRUNO_SOURCE_MODE ?? "auto"; +const remoteRepoUrl = process.env.BRUNO_REPO_URL; +const remoteRepoRef = process.env.BRUNO_REPO_REF ?? "main"; +const remoteCollectionPath = process.env.BRUNO_COLLECTION_PATH ?? "Solid Connection"; +const explicitCollectionDir = process.env.BRUNO_COLLECTION_DIR; + +function run(command, args, cwd = rootDir) { + const result = spawnSync(command, args, { + cwd, + stdio: "inherit", + env: process.env, + }); + + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +function ensureRemoteCollectionDir() { + if (!remoteRepoUrl) { + throw new Error("BRUNO_REPO_URL is required when BRUNO source is remote."); + } + + mkdirSync(cacheRoot, { recursive: true }); + rmSync(checkoutDir, { recursive: true, force: true }); + run("git", ["clone", "--depth", "1", "--branch", remoteRepoRef, remoteRepoUrl, checkoutDir]); + + const collectionDir = resolve(checkoutDir, remoteCollectionPath); + if (!existsSync(collectionDir)) { + throw new Error(`Bruno collection path does not exist: ${collectionDir}`); + } + + return collectionDir; +} + +function resolveCollectionDir() { + if (explicitCollectionDir) { + const fullPath = resolve(rootDir, explicitCollectionDir); + if (!existsSync(fullPath)) { + throw new Error(`BRUNO_COLLECTION_DIR does not exist: ${fullPath}`); + } + return fullPath; + } + + if (sourceMode === "local") { + if (!existsSync(defaultLocalCollectionDir)) { + throw new Error(`Local Bruno collection directory does not exist: ${defaultLocalCollectionDir}`); + } + return defaultLocalCollectionDir; + } + + if (sourceMode === "remote") { + return ensureRemoteCollectionDir(); + } + + if (existsSync(defaultLocalCollectionDir)) { + return defaultLocalCollectionDir; + } + + return ensureRemoteCollectionDir(); +} + +const collectionDir = resolveCollectionDir(); + +run("pnpm", ["-C", "../bruno-api-typescript", "run", "build"]); +run("node", [ + "../bruno-api-typescript/dist/cli/index.js", + "generate-hooks", + "-i", + collectionDir, + "-o", + "./src/apis", + "--axios-path", + "../axiosInstance", +]); From 1218cd85ff36426b5cf5d49dfe13ae9b81fbe87c Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 18:47:40 +0900 Subject: [PATCH 09/10] =?UTF-8?q?=F0=9F=90=9B=20=EB=8C=80=ED=95=99=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=99=88=EB=8C=80=ED=95=99=20=EB=A7=A4=ED=95=91=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/university/list/[homeUniversityName]/page.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/university/list/[homeUniversityName]/page.tsx b/apps/web/src/app/university/list/[homeUniversityName]/page.tsx index 3c370544..b427c9f3 100644 --- a/apps/web/src/app/university/list/[homeUniversityName]/page.tsx +++ b/apps/web/src/app/university/list/[homeUniversityName]/page.tsx @@ -2,7 +2,8 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import { HOME_UNIVERSITIES, HOME_UNIVERSITY_SLUG, type HomeUniversityName } from "@/types/university"; +import { HOME_UNIVERSITY_LIST, HOME_UNIVERSITY_SLUG_MAP } from "@/constants/university"; +import type { HomeUniversityName, HomeUniversitySlug } from "@/types/university"; import SearchResultsContent from "./SearchResultsContent"; @@ -11,7 +12,7 @@ export const revalidate = false; // 정적 경로 생성 (ISR) export async function generateStaticParams() { - return HOME_UNIVERSITIES.map((university) => ({ + return HOME_UNIVERSITY_LIST.map((university) => ({ homeUniversityName: university.slug, })); } @@ -23,7 +24,7 @@ type PageProps = { export async function generateMetadata({ params }: PageProps): Promise { const { homeUniversityName } = await params; - const universityName = HOME_UNIVERSITY_SLUG[homeUniversityName]; + const universityName = HOME_UNIVERSITY_SLUG_MAP[homeUniversityName as HomeUniversitySlug]; if (!universityName) { return { @@ -40,7 +41,7 @@ export async function generateMetadata({ params }: PageProps): Promise const UniversityListPage = async ({ params }: PageProps) => { const { homeUniversityName } = await params; - const universityName = HOME_UNIVERSITY_SLUG[homeUniversityName] as HomeUniversityName | undefined; + const universityName = HOME_UNIVERSITY_SLUG_MAP[homeUniversityName as HomeUniversitySlug] as HomeUniversityName | undefined; if (!universityName) { notFound(); From 5c0cadf47da4138781e9ad4cde1fb569f2b7db59 Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 18:52:49 +0900 Subject: [PATCH 10/10] =?UTF-8?q?=F0=9F=94=A7=20pnpm=20lockfile=20?= =?UTF-8?q?=EB=8F=99=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pnpm-lock.yaml | 3579 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 3506 insertions(+), 73 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 15b70bb7..aea0731b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,115 @@ importers: specifier: ^2.3.0 version: 2.7.5 + apps/admin: + dependencies: + '@radix-ui/react-label': + specifier: ^2.1.2 + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.4(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tailwindcss/vite': + specifier: ^4.0.6 + version: 4.1.18(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@tanstack/react-devtools': + specifier: ^0.7.0 + version: 0.7.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) + '@tanstack/react-router': + specifier: ^1.132.0 + version: 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router-devtools': + specifier: ^1.132.0 + version: 1.159.10(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.159.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router-ssr-query': + specifier: ^1.131.7 + version: 1.159.10(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.4))(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.159.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start': + specifier: ^1.132.0 + version: 1.159.11(crossws@0.4.4(srvx@0.11.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1) + '@tanstack/router-plugin': + specifier: ^1.132.0 + version: 1.159.11(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1) + axios: + specifier: ^1.6.7 + version: 1.13.2 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + lucide-react: + specifier: ^0.561.0 + version: 0.561.0(react@19.2.4) + nitro: + specifier: npm:nitro-nightly@latest + version: nitro-nightly@3.0.1-20260213-154614-f663e76d(chokidar@3.6.0)(dotenv@16.6.1)(jiti@2.6.1)(lru-cache@10.4.3)(rollup@4.55.1)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + react: + specifier: ^19.2.0 + version: 19.2.4 + react-dom: + specifier: ^19.2.0 + version: 19.2.4(react@19.2.4) + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + tailwind-merge: + specifier: ^3.0.2 + version: 3.4.0 + tailwindcss: + specifier: ^4.0.6 + version: 4.1.18 + vite-tsconfig-paths: + specifier: ^6.0.2 + version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + devDependencies: + '@biomejs/biome': + specifier: 2.2.4 + version: 2.2.4 + '@tanstack/devtools-vite': + specifier: ^0.3.11 + version: 0.3.12(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@testing-library/dom': + specifier: ^10.4.0 + version: 10.4.1 + '@testing-library/react': + specifier: ^16.2.0 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@types/node': + specifier: ^22.10.2 + version: 22.19.7 + '@types/react': + specifier: ^19.2.0 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.0 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^5.0.4 + version: 5.1.4(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + jsdom: + specifier: ^27.0.0 + version: 27.4.0 + typescript: + specifier: ^5.7.2 + version: 5.9.3 + vite: + specifier: ^7.1.7 + version: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: + specifier: ^3.0.5 + version: 3.2.4(@types/node@22.19.7)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + web-vitals: + specifier: ^5.1.0 + version: 5.1.0 + apps/web: dependencies: '@hookform/resolvers': @@ -34,16 +143,16 @@ importers: version: 14.2.35(next@14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@radix-ui/react-checkbox': specifier: ^1.1.4 - version: 1.3.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-label': specifier: ^2.1.2 - version: 2.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-progress': specifier: ^1.1.2 - version: 1.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-select': specifier: ^2.1.6 - version: 2.2.6(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@react-google-maps/api': specifier: ^2.19.2 version: 2.20.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -62,6 +171,9 @@ importers: '@tanstack/react-virtual': specifier: ^3.13.12 version: 3.13.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@vercel/speed-insights': + specifier: ^1.3.1 + version: 1.3.1(next@14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) axios: specifier: ^1.6.7 version: 1.13.2 @@ -106,13 +218,13 @@ importers: version: 3.4.0 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.19(yaml@2.8.2)) + version: 1.0.7(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)) zod: specifier: ^4.0.0 version: 4.3.6 zustand: specifier: ^5.0.7 - version: 5.0.10(@types/react@18.3.27)(react@18.3.1) + version: 5.0.10(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@svgr/webpack': specifier: ^8.1.0 @@ -121,8 +233,11 @@ importers: specifier: ^20.11.19 version: 20.19.30 '@types/react': - specifier: ^18.2.55 + specifier: 18.3.27 version: 18.3.27 + '@types/react-dom': + specifier: 18.3.7 + version: 18.3.7(@types/react@18.3.27) autoprefixer: specifier: ^10.4.20 version: 10.4.23(postcss@8.5.6) @@ -134,7 +249,7 @@ importers: version: 8.5.6 tailwindcss: specifier: ^3.4.10 - version: 3.4.19(yaml@2.8.2) + version: 3.4.19(tsx@4.21.0)(yaml@2.8.2) typescript: specifier: ^5.3.3 version: 5.9.3 @@ -164,8 +279,13 @@ importers: specifier: ^5.3.3 version: 5.9.3 + packages/config: {} + packages: + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -176,10 +296,27 @@ packages: '@apm-js-collab/tracing-hooks@0.3.1': resolution: {integrity: sha512-Vu1CbmPURlN5fTboVuKMoJjbO5qcq9fA5YXpskx3dXe/zTBvjODFoerw+69rVBlRLrJpwPqSDqEuJDEKIrTldw==} + '@asamuzakjp/css-color@4.1.2': + resolution: {integrity: sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==} + + '@asamuzakjp/dom-selector@6.7.8': + resolution: {integrity: sha512-stisC1nULNc9oH5lakAj8MH88ZxeGxzyWNDfbdCxvJSJIvDsHNZqYvscGTgy/ysgXWLJPt6K/4t0/GjvtKcFJQ==} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.6': resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} engines: {node: '>=6.9.0'} @@ -188,10 +325,18 @@ packages: resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} engines: {node: '>=6.9.0'} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.6': resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -284,6 +429,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} @@ -602,6 +752,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx@7.28.6': resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} engines: {node: '>=6.9.0'} @@ -715,6 +877,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -723,57 +889,118 @@ packages: resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.6': resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@biomejs/biome@2.2.4': + resolution: {integrity: sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==} + engines: {node: '>=14.21.3'} + hasBin: true + '@biomejs/biome@2.3.12': resolution: {integrity: sha512-AR7h4aSlAvXj7TAajW/V12BOw2EiS0AqZWV5dGozf4nlLoUF/ifvD0+YgKSskT0ylA6dY1A8AwgP8kZ6yaCQnA==} engines: {node: '>=14.21.3'} hasBin: true + '@biomejs/cli-darwin-arm64@2.2.4': + resolution: {integrity: sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + '@biomejs/cli-darwin-arm64@2.3.12': resolution: {integrity: sha512-cO6fn+KiMBemva6EARDLQBxeyvLzgidaFRJi8G7OeRqz54kWK0E+uSjgFaiHlc3DZYoa0+1UFE8mDxozpc9ieg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] + '@biomejs/cli-darwin-x64@2.2.4': + resolution: {integrity: sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + '@biomejs/cli-darwin-x64@2.3.12': resolution: {integrity: sha512-/fiF/qmudKwSdvmSrSe/gOTkW77mHHkH8Iy7YC2rmpLuk27kbaUOPa7kPiH5l+3lJzTUfU/t6x1OuIq/7SGtxg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] + '@biomejs/cli-linux-arm64-musl@2.2.4': + resolution: {integrity: sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + '@biomejs/cli-linux-arm64-musl@2.3.12': resolution: {integrity: sha512-aqkeSf7IH+wkzFpKeDVPSXy9uDjxtLpYA6yzkYsY+tVjwFFirSuajHDI3ul8en90XNs1NA0n8kgBrjwRi5JeyA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + '@biomejs/cli-linux-arm64@2.2.4': + resolution: {integrity: sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + '@biomejs/cli-linux-arm64@2.3.12': resolution: {integrity: sha512-nbOsuQROa3DLla5vvsTZg+T5WVPGi9/vYxETm9BOuLHBJN3oWQIg3MIkE2OfL18df1ZtNkqXkH6Yg9mdTPem7A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + '@biomejs/cli-linux-x64-musl@2.2.4': + resolution: {integrity: sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + '@biomejs/cli-linux-x64-musl@2.3.12': resolution: {integrity: sha512-kVGWtupRRsOjvw47YFkk5mLiAdpCPMWBo1jOwAzh+juDpUb2sWarIp+iq+CPL1Wt0LLZnYtP7hH5kD6fskcxmg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + '@biomejs/cli-linux-x64@2.2.4': + resolution: {integrity: sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + '@biomejs/cli-linux-x64@2.3.12': resolution: {integrity: sha512-CQtqrJ+qEEI8tgRSTjjzk6wJAwfH3wQlkIGsM5dlecfRZaoT+XCms/mf7G4kWNexrke6mnkRzNy6w8ebV177ow==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + '@biomejs/cli-win32-arm64@2.2.4': + resolution: {integrity: sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + '@biomejs/cli-win32-arm64@2.3.12': resolution: {integrity: sha512-Re4I7UnOoyE4kHMqpgtG6UvSBGBbbtvsOvBROgCCoH7EgANN6plSQhvo2W7OCITvTp7gD6oZOyZy72lUdXjqZg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] + '@biomejs/cli-win32-x64@2.2.4': + resolution: {integrity: sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + '@biomejs/cli-win32-x64@2.3.12': resolution: {integrity: sha512-qqGVWqNNek0KikwPZlOIoxtXgsNGsX+rgdEzgw82Re8nF02W+E2WokaQhpF5TdBh/D/RQ3TLppH+otp6ztN0lw==} engines: {node: '>=14.21.3'} @@ -849,6 +1076,211 @@ packages: resolution: {integrity: sha512-VmIFV/JkBRhDRRv7N5B7zEUkNZIx9Mp+8Pe65erz0rKycXLsi8Epcw0XJ+btSeRXgTzE7DyOyA9bkJ9mn/yqVQ==} engines: {node: '>=v18'} + '@csstools/color-helpers@6.0.1': + resolution: {integrity: sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.1.1': + resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.0.1': + resolution: {integrity: sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.0.27': + resolution: {integrity: sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==} + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@exodus/bytes@1.14.1': + resolution: {integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@fastify/busboy@3.2.0': resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==} @@ -965,6 +1397,9 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@next/env@14.2.35': resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} @@ -1040,6 +1475,22 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@oozcitak/dom@2.0.2': + resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} + engines: {node: '>=20.0'} + + '@oozcitak/infra@2.0.2': + resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==} + engines: {node: '>=20.0'} + + '@oozcitak/url@3.0.0': + resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==} + engines: {node: '>=20.0'} + + '@oozcitak/util@10.0.0': + resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} + engines: {node: '>=20.0'} + '@opentelemetry/api-logs@0.208.0': resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} engines: {node: '>=8.0.0'} @@ -1230,6 +1681,9 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 + '@oxc-project/types@0.113.0': + resolution: {integrity: sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1485,6 +1939,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-select@2.2.6': resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} peerDependencies: @@ -1516,6 +1983,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-use-callback-ref@1.1.1': resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: @@ -1616,23 +2096,109 @@ packages: '@react-google-maps/marker-clusterer@2.20.0': resolution: {integrity: sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==} - '@rollup/plugin-commonjs@28.0.1': - resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} - engines: {node: '>=16.0.0 || 14 >= 14.17'} - peerDependencies: - rollup: ^2.68.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + '@rolldown/binding-android-arm64@1.0.0-rc.4': + resolution: {integrity: sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@rollup/pluginutils@5.3.0': - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.4': + resolution: {integrity: sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.4': + resolution: {integrity: sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.4': + resolution: {integrity: sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4': + resolution: {integrity: sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4': + resolution: {integrity: sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.4': + resolution: {integrity: sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.4': + resolution: {integrity: sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.4': + resolution: {integrity: sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.4': + resolution: {integrity: sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.4': + resolution: {integrity: sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4': + resolution: {integrity: sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.4': + resolution: {integrity: sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.40': + resolution: {integrity: sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==} + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rolldown/pluginutils@1.0.0-rc.4': + resolution: {integrity: sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==} + + '@rollup/plugin-commonjs@28.0.1': + resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true '@rollup/rollup-android-arm-eabi@4.55.1': resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} @@ -1891,6 +2457,36 @@ packages: peerDependencies: webpack: '>=4.40.0' + '@solid-primitives/event-listener@2.4.3': + resolution: {integrity: sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/keyboard@1.3.3': + resolution: {integrity: sha512-9dQHTTgLBqyAI7aavtO+HnpTVJgWQA1ghBSrmLtMu1SMxLPDuLfuNr+Tk5udb4AL4Ojg7h9JrKOGEEDqsJXWJA==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/resize-observer@2.1.3': + resolution: {integrity: sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/rootless@1.5.2': + resolution: {integrity: sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/static-store@0.1.2': + resolution: {integrity: sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/utils@6.3.2': + resolution: {integrity: sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ==} + peerDependencies: + solid-js: ^1.6.12 + '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} @@ -1981,12 +2577,153 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.18': + resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tanstack/devtools-client@0.0.3': + resolution: {integrity: sha512-kl0r6N5iIL3t9gGDRAv55VRM3UIyMKVH83esRGq7xBjYsRLe/BeCIN2HqrlJkObUXQMKhy7i8ejuGOn+bDqDBw==} + engines: {node: '>=18'} + + '@tanstack/devtools-client@0.0.5': + resolution: {integrity: sha512-hsNDE3iu4frt9cC2ppn1mNRnLKo2uc1/1hXAyY9z4UYb+o40M2clFAhiFoo4HngjfGJDV3x18KVVIq7W4Un+zA==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-bus@0.3.3': + resolution: {integrity: sha512-lWl88uLAz7ZhwNdLH6A3tBOSEuBCrvnY9Fzr5JPdzJRFdM5ZFdyNWz1Bf5l/F3GU57VodrN0KCFi9OA26H5Kpg==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-client@0.3.5': + resolution: {integrity: sha512-RL1f5ZlfZMpghrCIdzl6mLOFLTuhqmPNblZgBaeKfdtk5rfbjykurv+VfYydOFXj0vxVIoA2d/zT7xfD7Ph8fw==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-client@0.4.0': + resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==} + engines: {node: '>=18'} + + '@tanstack/devtools-ui@0.4.4': + resolution: {integrity: sha512-5xHXFyX3nom0UaNfiOM92o6ziaHjGo3mcSGe2HD5Xs8dWRZNpdZ0Smd0B9ddEhy0oB+gXyMzZgUJb9DmrZV0Mg==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + + '@tanstack/devtools-vite@0.3.12': + resolution: {integrity: sha512-fGJgu4xUhKmGk+a+/aHD8l5HKVk6+ObA+6D3YC3xCXbai/YmaGhztqcZf1tKUqjZyYyQLHsjqmKzvJgVpQP1jw==} + engines: {node: '>=18'} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 + + '@tanstack/devtools@0.7.0': + resolution: {integrity: sha512-AlAoCqJhWLg9GBEaoV1g/j+X/WA1aJSWOsekxeuZpYeS2hdVuKAjj04KQLUMJhtLfNl2s2E+TCj7ZRtWyY3U4w==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + + '@tanstack/history@1.154.14': + resolution: {integrity: sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA==} + engines: {node: '>=12'} + '@tanstack/query-core@5.90.19': resolution: {integrity: sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==} '@tanstack/query-devtools@5.92.0': resolution: {integrity: sha512-N8D27KH1vEpVacvZgJL27xC6yPFUy0Zkezn5gnB3L3gRCxlDeSuiya7fKge8Y91uMTnC8aSxBQhcK6ocY7alpQ==} + '@tanstack/react-devtools@0.7.11': + resolution: {integrity: sha512-a2Lmz8x+JoDrsU6f7uKRcyyY+k8mA/n5mb9h7XJ3Fz/y3+sPV9t7vAW1s5lyNkQyyDt6V1Oim99faLthoJSxMw==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': '>=16.8' + '@types/react-dom': '>=16.8' + react: '>=16.8' + react-dom: '>=16.8' + '@tanstack/react-query-devtools@5.91.2': resolution: {integrity: sha512-ZJ1503ay5fFeEYFUdo7LMNFzZryi6B0Cacrgr2h1JRkvikK1khgIq6Nq2EcblqEdIlgB/r7XDW8f8DQ89RuUgg==} peerDependencies: @@ -1998,15 +2735,170 @@ packages: peerDependencies: react: ^18 || ^19 + '@tanstack/react-router-devtools@1.159.10': + resolution: {integrity: sha512-dfaXh7WBz1HJ639oMix5hJUJWCxrpcINPVXiN/3CBPYuGB2wYsBG2Iw61yufp+KkuFatAy95VTTnyeqGOq8ysw==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/react-router': ^1.159.10 + '@tanstack/router-core': ^1.159.9 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true + + '@tanstack/react-router-ssr-query@1.159.10': + resolution: {integrity: sha512-kaYlYgGxG5jzRBlgrYtbXKZdSbwA24rsvJgBVCp61CYKBEPHVBZHh0Qz7FEActEIHKI+Palow4fJxwa2DYu1IQ==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/query-core': '>=5.90.0' + '@tanstack/react-query': '>=5.90.0' + '@tanstack/react-router': '>=1.127.0' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-router@1.159.10': + resolution: {integrity: sha512-PQO6hpnqNALmotXasfCafVBWWKpxChmYbXRjwPZQQq8au7m71z4WtAHsmUA2v/uqqhsvE9ySyWVx/Ece/Uq2ZQ==} + engines: {node: '>=12'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start-client@1.159.10': + resolution: {integrity: sha512-w2k///dPf/u1wWE3SWT1dEzwRQdhPv0KIrBSWCgvs/SY+N7IDpT2VXMaom1UqNSyQil7k+6oBECvTnMl8fxhpA==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start-server@1.159.10': + resolution: {integrity: sha512-ND4nMxAxNu/wRw3ZMZLRsWZogGiMAjAp9O8eNrCeYvPHoxknTUenI3Rksd9kpwCQSZSR+fLGMd1qC4kE2Adclg==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start@1.159.11': + resolution: {integrity: sha512-PbHpFEvu35XOH9MQCgcDGiTZ9UCgYpjpwgPtFAV9yyzFTqmojnhsezK1CU4XmUdvzw5IRb5s1PDsMUw13K3iVw==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + vite: '>=7.0.0' + + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-virtual@3.13.18': resolution: {integrity: sha512-dZkhyfahpvlaV0rIKnvQiVoWPyURppl6w4m9IwMDpuIjcJ1sD9YGWrt0wISvgU7ewACXx2Ct46WPgI6qAD4v6A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/router-core@1.159.9': + resolution: {integrity: sha512-A9B8gvklvMCjSAFG8nDAhfmROI8kjcij8wzznQaw4RfGIOrYXyNe5fCAcbHXGpgNeTE2JnK75b6AjidDPQfrmw==} + engines: {node: '>=12'} + + '@tanstack/router-devtools-core@1.159.9': + resolution: {integrity: sha512-2b1zmN12qOhuxAYq5EEtecDmj1ekA8i7yKKDXc2WYCwc6W2sqz+JMoKDwGzAIrC8rHpe4n0+eU3r1re5VnIPcg==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/router-core': ^1.159.9 + csstype: ^3.0.10 + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-generator@1.159.9': + resolution: {integrity: sha512-WDn17uYP/Mk//7OP5ZnlYK228ezQ/N+pVA8BrwoF69g3Scq5CkfZUD633UI1+oXIl8Fb1pCt4CU0LkN7niMTmQ==} + engines: {node: '>=12'} + + '@tanstack/router-plugin@1.159.11': + resolution: {integrity: sha512-QrnwUX9XtfOqiNsD/AYmqTvvezuUwv4W7ewWwUgSTe0CEkuyjEa8aiZMLrofB613lRmoHSmjT6ciaV3z2vHdWw==} + engines: {node: '>=12'} + peerDependencies: + '@rsbuild/core': '>=1.0.2' + '@tanstack/react-router': ^1.159.10 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' + vite-plugin-solid: ^2.11.10 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-ssr-query-core@1.159.9': + resolution: {integrity: sha512-IGmoh+wLhdcB0lU3wNJUBR1u9Y//OwxtjgsP/6KIr6jSbcnN1rPxs8FryPutaH82GksMQbmlzvxkLJwQCVhd5g==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/query-core': '>=5.90.0' + '@tanstack/router-core': '>=1.127.0' + + '@tanstack/router-utils@1.158.0': + resolution: {integrity: sha512-qZ76eaLKU6Ae9iI/mc5zizBX149DXXZkBVVO3/QRIll79uKLJZHQlMKR++2ba7JsciBWz1pgpIBcCJPE9S0LVg==} + engines: {node: '>=12'} + + '@tanstack/start-client-core@1.159.9': + resolution: {integrity: sha512-87gI1JcMIJygSrDY+6TFGOG7jRCFxjkg0YIqdngBA1o/IMUDwQJdJuI4IgKV55RypMLjSbHpCeSdgtv3Fb1eFg==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-fn-stubs@1.154.7': + resolution: {integrity: sha512-D69B78L6pcFN5X5PHaydv7CScQcKLzJeEYqs7jpuyyqGQHSUIZUjS955j+Sir8cHhuDIovCe2LmsYHeZfWf3dQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-plugin-core@1.159.11': + resolution: {integrity: sha512-HUNEpkbBRPG0fYS6JPU9nJGZ8IPZAIa078Vet1kXH2ClOL5msr1rOJGrc2tP0vUTDnenFjhszHExnMBlYcusRA==} + engines: {node: '>=22.12.0'} + peerDependencies: + vite: '>=7.0.0' + + '@tanstack/start-server-core@1.159.9': + resolution: {integrity: sha512-ora5NziE6roXvJHva4T9s+qlTWtig1WSG75J8ToAFE/C1FyGuGPzmKiEok5x+D9stYUDnlU12Nn+zCyIuZi/fQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-storage-context@1.159.9': + resolution: {integrity: sha512-tBWBQnj6lt6EJ6UuheycVMG9so9lyi/mqKLHylxlZwnCdGdkI5+dRAuQWqnlhNrJaP0teddgQjRcXPLK583GlQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@tanstack/virtual-core@3.13.18': resolution: {integrity: sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==} + '@tanstack/virtual-file-routes@1.154.7': + resolution: {integrity: sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg==} + engines: {node: '>=12'} + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -2015,15 +2907,39 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/caseless@0.12.5': resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} '@types/conventional-commits-parser@5.0.2': resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -2066,9 +2982,22 @@ packages: '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react@18.3.27': resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/request@2.48.13': resolution: {integrity: sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==} @@ -2078,6 +3007,64 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@vercel/speed-insights@1.3.1': + resolution: {integrity: sha512-PbEr7FrMkUrGYvlcLHGkXdCkxnylCWePx7lPxxq36DNdfo9mcUjLOmqOyPDHAOgnfqgGGdmE3XI9L/4+5fr+vQ==} + peerDependencies: + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + + '@vitejs/plugin-react@5.1.4': + resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -2189,10 +3176,18 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -2210,6 +3205,9 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} @@ -2217,6 +3215,14 @@ packages: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} @@ -2233,6 +3239,9 @@ packages: axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + babel-plugin-polyfill-corejs2@0.4.14: resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} peerDependencies: @@ -2258,6 +3267,9 @@ packages: resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} hasBin: true + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -2290,6 +3302,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2309,6 +3325,10 @@ packages: caniuse-lite@1.0.30001764: resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -2317,6 +3337,17 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -2374,6 +3405,10 @@ packages: compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + conventional-changelog-angular@7.0.0: resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} engines: {node: '>=16'} @@ -2390,6 +3425,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + core-js-compat@3.47.0: resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} @@ -2426,6 +3464,14 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crossws@0.4.4: + resolution: {integrity: sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg==} + peerDependencies: + srvx: '>=0.7.1' + peerDependenciesMeta: + srvx: + optional: true + css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -2437,6 +3483,10 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.2.2: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} @@ -2450,6 +3500,10 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssstyle@5.3.7: + resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} + engines: {node: '>=20'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2457,6 +3511,36 @@ packages: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} + data-urls@6.0.1: + resolution: {integrity: sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==} + engines: {node: '>=20'} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + db0@0.3.4: + resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} + peerDependencies: + '@electric-sql/pglite': '*' + '@libsql/client': '*' + better-sqlite3: '*' + drizzle-orm: '*' + mysql2: '*' + sqlite3: '*' + peerDependenciesMeta: + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + better-sqlite3: + optional: true + drizzle-orm: + optional: true + mysql2: + optional: true + sqlite3: + optional: true + debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -2474,6 +3558,13 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -2482,15 +3573,30 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -2537,6 +3643,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -2548,6 +3657,14 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -2563,6 +3680,9 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} @@ -2574,6 +3694,11 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2582,6 +3707,11 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -2597,6 +3727,9 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -2613,6 +3746,13 @@ packages: resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} engines: {node: '>=12.0.0'} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -2732,6 +3872,9 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} @@ -2756,6 +3899,14 @@ packages: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 + google-auth-library@9.15.1: resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} engines: {node: '>=14'} @@ -2779,6 +3930,16 @@ packages: resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} engines: {node: '>=14.0.0'} + h3@2.0.1-rc.14: + resolution: {integrity: sha512-163qbGmTr/9rqQRNuqMqtgXnOUAkE4KTdauiC9y0E5iG1I65kte9NyfWvZw5RTDMt6eY+DtyoNzrQ9wA2BfvGQ==} + engines: {node: '>=20.11.1'} + hasBin: true + peerDependencies: + crossws: ^0.4.1 + peerDependenciesMeta: + crossws: + optional: true + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -2795,9 +3956,19 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hookable@6.0.1: + resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} + + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} @@ -2808,6 +3979,10 @@ packages: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -2821,6 +3996,10 @@ packages: engines: {node: '>=18'} hasBin: true + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -2872,6 +4051,9 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -2883,6 +4065,10 @@ packages: resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} engines: {node: '>=8'} + isbot@5.1.35: + resolution: {integrity: sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2907,10 +4093,22 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsdom@27.4.0: + resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -2951,6 +4149,79 @@ packages: kdbush@4.0.2: resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} + launch-editor@2.12.0: + resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -3040,12 +4311,19 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3061,6 +4339,15 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lucide-react@0.561.0: + resolution: {integrity: sha512-Y59gMY38tl4/i0qewcqohPdEbieBy7SovpBL9IFebhc2mDd8x4PZSOsiFRkpPcOq6bj1r/mjH/Rk73gSlIJP2A==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3078,6 +4365,9 @@ packages: mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} @@ -3157,6 +4447,34 @@ packages: sass: optional: true + nf3@0.3.10: + resolution: {integrity: sha512-UlqmHkZiHGgSkRj17yrOXEsSu5ECvtlJ3Xm1W5WsWrTKgu9m7OjrMZh9H/ME2LcWrTlMD0/vmmNVpyBG4yRdGg==} + + nitro-nightly@3.0.1-20260213-154614-f663e76d: + resolution: {integrity: sha512-TmbHSdWphd8T/ZNK63OkHamSMaaf44G3YD2KQwTlz742MbqUHRdln8r2CFdAJ2lDQJ1xRo82hXpsO4C32R8YuQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + dotenv: '*' + giget: '*' + jiti: ^2.6.1 + rollup: ^4.57.1 + vite: ^7 || ^8 || >=8.0.0-0 + xml2js: ^0.6.2 + peerDependenciesMeta: + dotenv: + optional: true + giget: + optional: true + jiti: + optional: true + rollup: + optional: true + vite: + optional: true + xml2js: + optional: true + no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -3191,6 +4509,12 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + ofetch@2.0.0-alpha.3: + resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3221,6 +4545,18 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3244,6 +4580,13 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -3344,6 +4687,15 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -3359,6 +4711,10 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -3373,12 +4729,24 @@ packages: peerDependencies: react: ^18.3.1 + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + react-hook-form@7.71.1: resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -3413,6 +4781,10 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -3424,6 +4796,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + regenerate-unicode-properties@10.2.2: resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} engines: {node: '>=4'} @@ -3465,6 +4841,9 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} @@ -3482,20 +4861,38 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rolldown@1.0.0-rc.4: + resolution: {integrity: sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.55.1: resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rou3@0.7.12: + resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} @@ -3512,6 +4909,16 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + seroval-plugins@1.5.0: + resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.5.0: + resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==} + engines: {node: '>=10'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3520,6 +4927,13 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -3531,6 +4945,15 @@ packages: resolution: {integrity: sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==} engines: {node: '>=12'} + solid-js@1.9.11: + resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3542,14 +4965,29 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + srvx@0.11.4: + resolution: {integrity: sha512-m/2p87bqWZ94xpRN06qNBwh0xq/D0dXajnvPDSHFqrTogxuTWYNP1UHz6Cf+oY7D+NPLY35TJAp4ESIKn0WArQ==} + engines: {node: '>=20.16.0'} + hasBin: true + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stacktrace-parser@0.1.11: resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} engines: {node: '>=6'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stream-events@1.0.5: resolution: {integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==} @@ -3579,6 +5017,9 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} @@ -3626,6 +5067,9 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tailwind-merge@3.4.0: resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} @@ -3639,6 +5083,9 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -3685,6 +5132,18 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -3693,19 +5152,61 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + tldts-core@7.0.23: + resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==} + + tldts@7.0.23: + resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + turbo-darwin-64@2.7.5: resolution: {integrity: sha512-nN3wfLLj4OES/7awYyyM7fkU8U8sAFxsXau2bYJwAWi6T09jd87DgHD8N31zXaJ7LcpyppHWPRI2Ov9MuZEwnQ==} cpu: [x64] @@ -3749,9 +5250,19 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@7.22.0: + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -3775,6 +5286,84 @@ packages: unplugin@1.0.1: resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unstorage@2.0.0-alpha.5: + resolution: {integrity: sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g==} + peerDependencies: + '@azure/app-configuration': ^1.9.0 + '@azure/cosmos': ^4.7.0 + '@azure/data-tables': ^13.3.1 + '@azure/identity': ^4.13.0 + '@azure/keyvault-secrets': ^4.10.0 + '@azure/storage-blob': ^12.29.1 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.12.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.35.6 + '@vercel/blob': '>=0.27.3' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + chokidar: ^4 || ^5 + db0: '>=0.3.4' + idb-keyval: ^6.2.2 + ioredis: ^5.8.2 + lru-cache: ^11.2.2 + mongodb: ^6 || ^7 + ofetch: '*' + uploadthing: ^7.7.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + chokidar: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + lru-cache: + optional: true + mongodb: + optional: true + ofetch: + optional: true + uploadthing: + optional: true + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -3804,6 +5393,11 @@ packages: '@types/react': optional: true + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3819,13 +5413,110 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite-tsconfig-paths@6.1.1: + resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==} + peerDependencies: + vite: '*' + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + watchpack@2.5.1: resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} + web-vitals@5.1.0: + resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + webpack-sources@3.3.3: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} @@ -3833,6 +5524,9 @@ packages: webpack-virtual-modules@0.5.0: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + webpack@5.104.1: resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} @@ -3851,6 +5545,23 @@ packages: resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} engines: {node: '>=0.8.0'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -3859,16 +5570,44 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + 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 + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlbuilder2@4.0.3: + resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} + engines: {node: '>=20.0'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} @@ -3905,6 +5644,9 @@ packages: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} @@ -3928,6 +5670,8 @@ packages: snapshots: + '@acemir/cssom@0.9.31': {} + '@alloc/quick-lru@5.2.0': {} '@apm-js-collab/code-transformer@0.8.2': {} @@ -3940,12 +5684,42 @@ snapshots: transitivePeerDependencies: - supports-color + '@asamuzakjp/css-color@4.1.2': + dependencies: + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.2.6 + + '@asamuzakjp/dom-selector@6.7.8': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.6 + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.28.6': {} '@babel/core@7.28.6': @@ -3968,6 +5742,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/generator@7.28.6': dependencies: '@babel/parser': 7.28.6 @@ -3976,6 +5770,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.28.6 @@ -4044,6 +5846,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.6 + transitivePeerDependencies: + - supports-color + '@babel/helper-optimise-call-expression@7.27.1': dependencies: '@babel/types': 7.28.6 @@ -4098,6 +5909,10 @@ snapshots: dependencies: '@babel/types': 7.28.6 + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 @@ -4446,6 +6261,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 @@ -4647,6 +6472,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/runtime@7.28.6': {} + '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.28.6 @@ -4665,11 +6492,39 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@biomejs/biome@2.2.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.2.4 + '@biomejs/cli-darwin-x64': 2.2.4 + '@biomejs/cli-linux-arm64': 2.2.4 + '@biomejs/cli-linux-arm64-musl': 2.2.4 + '@biomejs/cli-linux-x64': 2.2.4 + '@biomejs/cli-linux-x64-musl': 2.2.4 + '@biomejs/cli-win32-arm64': 2.2.4 + '@biomejs/cli-win32-x64': 2.2.4 + '@biomejs/biome@2.3.12': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.3.12 @@ -4681,27 +6536,51 @@ snapshots: '@biomejs/cli-win32-arm64': 2.3.12 '@biomejs/cli-win32-x64': 2.3.12 + '@biomejs/cli-darwin-arm64@2.2.4': + optional: true + '@biomejs/cli-darwin-arm64@2.3.12': optional: true + '@biomejs/cli-darwin-x64@2.2.4': + optional: true + '@biomejs/cli-darwin-x64@2.3.12': optional: true + '@biomejs/cli-linux-arm64-musl@2.2.4': + optional: true + '@biomejs/cli-linux-arm64-musl@2.3.12': optional: true + '@biomejs/cli-linux-arm64@2.2.4': + optional: true + '@biomejs/cli-linux-arm64@2.3.12': optional: true + '@biomejs/cli-linux-x64-musl@2.2.4': + optional: true + '@biomejs/cli-linux-x64-musl@2.3.12': optional: true + '@biomejs/cli-linux-x64@2.2.4': + optional: true + '@biomejs/cli-linux-x64@2.3.12': optional: true + '@biomejs/cli-win32-arm64@2.2.4': + optional: true + '@biomejs/cli-win32-arm64@2.3.12': optional: true + '@biomejs/cli-win32-x64@2.2.4': + optional: true + '@biomejs/cli-win32-x64@2.3.12': optional: true @@ -4815,6 +6694,124 @@ snapshots: '@types/conventional-commits-parser': 5.0.2 chalk: 5.6.2 + '@csstools/color-helpers@6.0.1': {} + + '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.0.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.1 + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.0.27': {} + + '@csstools/css-tokenizer@4.0.0': {} + + '@emnapi/core@1.8.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@exodus/bytes@1.14.1': {} + '@fastify/busboy@3.2.0': {} '@firebase/app-check-interop-types@0.3.2': {} @@ -4993,6 +6990,13 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': optional: true + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@next/env@14.2.35': {} '@next/swc-darwin-arm64@14.2.33': @@ -5040,6 +7044,23 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@oozcitak/dom@2.0.2': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/url': 3.0.0 + '@oozcitak/util': 10.0.0 + + '@oozcitak/infra@2.0.2': + dependencies: + '@oozcitak/util': 10.0.0 + + '@oozcitak/url@3.0.0': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + + '@oozcitak/util@10.0.0': {} + '@opentelemetry/api-logs@0.208.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -5276,6 +7297,8 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@oxc-project/types@0.113.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -5323,21 +7346,22 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-arrow@1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-checkbox@1.3.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -5345,17 +7369,31 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-collection@1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.2.3(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -5363,12 +7401,24 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-context@1.1.2(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-context@1.1.3(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 @@ -5381,17 +7431,24 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -5399,15 +7456,16 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-focus-scope@1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/react-id@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -5416,21 +7474,38 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-label@2.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) + + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-popper@1.2.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -5440,17 +7515,19 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-portal@1.1.9(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-presence@1.1.5(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -5458,59 +7535,109 @@ snapshots: react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) - '@radix-ui/react-primitive@2.1.4(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-slot': 1.2.4(@types/react@18.3.27)(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) + + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-progress@1.1.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-context': 1.1.3(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-select@2.2.6(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-direction': 1.1.1(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-id': 1.1.1(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-slot': 1.2.3(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.27)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) aria-hidden: 1.2.6 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-remove-scroll: 2.7.2(@types/react@18.3.27)(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/react-slot@1.2.3(@types/react@18.3.27)(react@18.3.1)': dependencies: @@ -5519,6 +7646,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-slot@1.2.4(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) @@ -5526,12 +7660,41 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-slot@1.2.4(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.27)(react@18.3.1) @@ -5540,6 +7703,14 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -5547,6 +7718,13 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.27)(react@18.3.1) @@ -5560,6 +7738,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.14 + '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.27)(react@18.3.1)': dependencies: react: 18.3.1 @@ -5580,13 +7764,14 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 - '@radix-ui/react-visually-hidden@1.2.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 18.3.27 + '@types/react-dom': 18.3.7(@types/react@18.3.27) '@radix-ui/rect@1.1.1': {} @@ -5601,9 +7786,56 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@react-google-maps/infobox@2.20.0': {} + '@react-google-maps/infobox@2.20.0': {} + + '@react-google-maps/marker-clusterer@2.20.0': {} + + '@rolldown/binding-android-arm64@1.0.0-rc.4': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.4': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.4': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.4': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.4': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.4': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.4': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.4': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.4': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.4': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.40': {} + + '@rolldown/pluginutils@1.0.0-rc.3': {} - '@react-google-maps/marker-clusterer@2.20.0': {} + '@rolldown/pluginutils@1.0.0-rc.4': {} '@rollup/plugin-commonjs@28.0.1(rollup@4.55.1)': dependencies: @@ -5900,6 +8132,40 @@ snapshots: - encoding - supports-color + '@solid-primitives/event-listener@2.4.3(solid-js@1.9.11)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 + + '@solid-primitives/keyboard@1.3.3(solid-js@1.9.11)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 + + '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.11)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) + '@solid-primitives/static-store': 0.1.2(solid-js@1.9.11) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 + + '@solid-primitives/rootless@1.5.2(solid-js@1.9.11)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 + + '@solid-primitives/static-store@0.1.2(solid-js@1.9.11)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 + + '@solid-primitives/utils@6.3.2(solid-js@1.9.11)': + dependencies: + solid-js: 1.9.11 + '@standard-schema/utils@0.3.0': {} '@stomp/stompjs@7.2.1': {} @@ -6004,10 +8270,154 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.8.1 + '@tailwindcss/node@4.1.18': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.4 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.18 + + '@tailwindcss/oxide-android-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide@4.1.18': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + tailwindcss: 4.1.18 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + + '@tanstack/devtools-client@0.0.3': + dependencies: + '@tanstack/devtools-event-client': 0.3.5 + + '@tanstack/devtools-client@0.0.5': + dependencies: + '@tanstack/devtools-event-client': 0.4.0 + + '@tanstack/devtools-event-bus@0.3.3': + dependencies: + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@tanstack/devtools-event-client@0.3.5': {} + + '@tanstack/devtools-event-client@0.4.0': {} + + '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.11)': + dependencies: + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + solid-js: 1.9.11 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools-vite@0.3.12(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + '@tanstack/devtools-client': 0.0.5 + '@tanstack/devtools-event-bus': 0.3.3 + chalk: 5.6.2 + launch-editor: 2.12.0 + picomatch: 4.0.3 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@tanstack/devtools@0.7.0(csstype@3.2.3)(solid-js@1.9.11)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) + '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.11) + '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.11) + '@tanstack/devtools-client': 0.0.3 + '@tanstack/devtools-event-bus': 0.3.3 + '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.11) + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + solid-js: 1.9.11 + transitivePeerDependencies: + - bufferutil + - csstype + - utf-8-validate + + '@tanstack/history@1.154.14': {} + '@tanstack/query-core@5.90.19': {} '@tanstack/query-devtools@5.92.0': {} + '@tanstack/react-devtools@0.7.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)': + dependencies: + '@tanstack/devtools': 0.7.0(csstype@3.2.3)(solid-js@1.9.11) + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - bufferutil + - csstype + - solid-js + - utf-8-validate + '@tanstack/react-query-devtools@5.91.2(@tanstack/react-query@5.90.19(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/query-devtools': 5.92.0 @@ -6019,22 +8429,297 @@ snapshots: '@tanstack/query-core': 5.90.19 react: 18.3.1 + '@tanstack/react-query@5.90.19(react@19.2.4)': + dependencies: + '@tanstack/query-core': 5.90.19 + react: 19.2.4 + + '@tanstack/react-router-devtools@1.159.10(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.159.9)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.159.9(@tanstack/router-core@1.159.9)(csstype@3.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@tanstack/router-core': 1.159.9 + transitivePeerDependencies: + - csstype + + '@tanstack/react-router-ssr-query@1.159.10(@tanstack/query-core@5.90.19)(@tanstack/react-query@5.90.19(react@19.2.4))(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.159.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/query-core': 5.90.19 + '@tanstack/react-query': 5.90.19(react@19.2.4) + '@tanstack/react-router': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-ssr-query-core': 1.159.9(@tanstack/query-core@5.90.19)(@tanstack/router-core@1.159.9) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@tanstack/router-core' + + '@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.154.14 + '@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.159.9 + isbot: 5.1.35 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-start-client@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.159.9 + '@tanstack/start-client-core': 1.159.9 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-start-server@1.159.10(crossws@0.4.4(srvx@0.11.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.154.14 + '@tanstack/react-router': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.159.9 + '@tanstack/start-client-core': 1.159.9 + '@tanstack/start-server-core': 1.159.9(crossws@0.4.4(srvx@0.11.4)) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - crossws + + '@tanstack/react-start@1.159.11(crossws@0.4.4(srvx@0.11.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1)': + dependencies: + '@tanstack/react-router': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-client': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-server': 1.159.10(crossws@0.4.4(srvx@0.11.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-utils': 1.158.0 + '@tanstack/start-client-core': 1.159.9 + '@tanstack/start-plugin-core': 1.159.11(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.11.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1) + '@tanstack/start-server-core': 1.159.9(crossws@0.4.4(srvx@0.11.4)) + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@rsbuild/core' + - crossws + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/react-store@0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.8.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + '@tanstack/react-virtual@3.13.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/virtual-core': 3.13.18 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + '@tanstack/router-core@1.159.9': + dependencies: + '@tanstack/history': 1.154.14 + '@tanstack/store': 0.8.0 + cookie-es: 2.0.0 + seroval: 1.5.0 + seroval-plugins: 1.5.0(seroval@1.5.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/router-devtools-core@1.159.9(@tanstack/router-core@1.159.9)(csstype@3.2.3)': + dependencies: + '@tanstack/router-core': 1.159.9 + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + tiny-invariant: 1.3.3 + optionalDependencies: + csstype: 3.2.3 + + '@tanstack/router-generator@1.159.9': + dependencies: + '@tanstack/router-core': 1.159.9 + '@tanstack/router-utils': 1.158.0 + '@tanstack/virtual-file-routes': 1.154.7 + prettier: 3.8.1 + recast: 0.23.11 + source-map: 0.7.6 + tsx: 4.21.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.159.11(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1)': + dependencies: + '@babel/core': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) + '@babel/template': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + '@tanstack/router-core': 1.159.9 + '@tanstack/router-generator': 1.159.9 + '@tanstack/router-utils': 1.158.0 + '@tanstack/virtual-file-routes': 1.154.7 + chokidar: 3.6.0 + unplugin: 2.3.11 + zod: 3.25.76 + optionalDependencies: + '@tanstack/react-router': 1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + webpack: 5.104.1 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-ssr-query-core@1.159.9(@tanstack/query-core@5.90.19)(@tanstack/router-core@1.159.9)': + dependencies: + '@tanstack/query-core': 5.90.19 + '@tanstack/router-core': 1.159.9 + + '@tanstack/router-utils@1.158.0': + dependencies: + '@babel/core': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + ansis: 4.2.0 + babel-dead-code-elimination: 1.0.12 + diff: 8.0.3 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - supports-color + + '@tanstack/start-client-core@1.159.9': + dependencies: + '@tanstack/router-core': 1.159.9 + '@tanstack/start-fn-stubs': 1.154.7 + '@tanstack/start-storage-context': 1.159.9 + seroval: 1.5.0 + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/start-fn-stubs@1.154.7': {} + + '@tanstack/start-plugin-core@1.159.11(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.4(srvx@0.11.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1)': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.28.6 + '@babel/types': 7.28.6 + '@rolldown/pluginutils': 1.0.0-beta.40 + '@tanstack/router-core': 1.159.9 + '@tanstack/router-generator': 1.159.9 + '@tanstack/router-plugin': 1.159.11(@tanstack/react-router@1.159.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(webpack@5.104.1) + '@tanstack/router-utils': 1.158.0 + '@tanstack/start-client-core': 1.159.9 + '@tanstack/start-server-core': 1.159.9(crossws@0.4.4(srvx@0.11.4)) + cheerio: 1.2.0 + exsolve: 1.0.8 + pathe: 2.0.3 + srvx: 0.11.4 + tinyglobby: 0.2.15 + ufo: 1.6.3 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vitefu: 1.1.1(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + xmlbuilder2: 4.0.3 + zod: 3.25.76 + transitivePeerDependencies: + - '@rsbuild/core' + - '@tanstack/react-router' + - crossws + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/start-server-core@1.159.9(crossws@0.4.4(srvx@0.11.4))': + dependencies: + '@tanstack/history': 1.154.14 + '@tanstack/router-core': 1.159.9 + '@tanstack/start-client-core': 1.159.9 + '@tanstack/start-storage-context': 1.159.9 + h3-v2: h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.11.4)) + seroval: 1.5.0 + tiny-invariant: 1.3.3 + transitivePeerDependencies: + - crossws + + '@tanstack/start-storage-context@1.159.9': + dependencies: + '@tanstack/router-core': 1.159.9 + + '@tanstack/store@0.8.0': {} + '@tanstack/virtual-core@3.13.18': {} + '@tanstack/virtual-file-routes@1.154.7': {} + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@tootallnate/once@2.0.0': optional: true '@trysound/sax@0.2.0': {} + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.6 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.6 + '@types/caseless@0.12.5': optional: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + '@types/connect@3.4.38': dependencies: '@types/node': 20.19.30 @@ -6043,6 +8728,8 @@ snapshots: dependencies: '@types/node': 20.19.30 + '@types/deep-eql@4.0.2': {} + '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -6093,11 +8780,23 @@ snapshots: '@types/prop-types@15.7.15': {} + '@types/react-dom@18.3.7(@types/react@18.3.27)': + dependencies: + '@types/react': 18.3.27 + + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + '@types/react@18.3.27': dependencies: '@types/prop-types': 15.7.15 csstype: 3.2.3 + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + '@types/request@2.48.13': dependencies: '@types/caseless': 0.12.5 @@ -6113,6 +8812,65 @@ snapshots: '@types/tough-cookie@4.0.5': optional: true + '@vercel/speed-insights@1.3.1(next@14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + optionalDependencies: + next: 14.2.35(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + + '@vitejs/plugin-react@5.1.4(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -6219,8 +8977,7 @@ snapshots: transitivePeerDependencies: - supports-color - agent-base@7.1.4: - optional: true + agent-base@7.1.4: {} ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: @@ -6246,8 +9003,12 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} + ansis@4.2.0: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -6263,11 +9024,21 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + array-ify@1.0.0: {} arrify@2.0.1: optional: true + assertion-error@2.0.1: {} + + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + async-retry@1.3.3: dependencies: retry: 0.13.1 @@ -6292,6 +9063,15 @@ snapshots: transitivePeerDependencies: - debug + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.6): dependencies: '@babel/compat-data': 7.28.6 @@ -6323,6 +9103,10 @@ snapshots: baseline-browser-mapping@2.9.15: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + bignumber.js@9.3.1: optional: true @@ -6354,6 +9138,8 @@ snapshots: dependencies: streamsearch: 1.1.0 + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -6367,6 +9153,14 @@ snapshots: caniuse-lite@1.0.30001764: {} + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -6374,6 +9168,31 @@ snapshots: chalk@5.6.2: {} + check-error@2.1.3: {} + + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.2.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.22.0 + whatwg-mimetype: 4.0.0 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -6429,6 +9248,8 @@ snapshots: array-ify: 1.0.0 dot-prop: 5.3.0 + consola@3.4.2: {} + conventional-changelog-angular@7.0.0: dependencies: compare-func: 2.0.0 @@ -6446,6 +9267,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@2.0.0: {} + core-js-compat@3.47.0: dependencies: browserslist: 4.28.1 @@ -6491,6 +9314,10 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crossws@0.4.4(srvx@0.11.4): + optionalDependencies: + srvx: 0.11.4 + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -6509,6 +9336,11 @@ snapshots: mdn-data: 2.0.30 source-map-js: 1.2.1 + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + css-what@6.2.2: {} cssesc@3.0.0: {} @@ -6517,10 +9349,26 @@ snapshots: dependencies: css-tree: 2.2.1 + cssstyle@5.3.7: + dependencies: + '@asamuzakjp/css-color': 4.1.2 + '@csstools/css-syntax-patches-for-csstree': 1.0.27 + css-tree: 3.1.0 + lru-cache: 11.2.6 + csstype@3.2.3: {} dargs@8.1.0: {} + data-urls@6.0.1: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 15.1.0 + + date-fns@4.1.0: {} + + db0@0.3.4: {} + debug@3.2.7: dependencies: ms: 2.1.3 @@ -6529,16 +9377,28 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + + deep-eql@5.0.2: {} + deepmerge@4.3.1: {} delayed-stream@1.0.0: {} + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + detect-node-es@1.1.0: {} didyoumean@1.2.2: {} + diff@8.0.3: {} + dlv@1.1.3: {} + dom-accessibility-api@0.5.16: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -6594,6 +9454,11 @@ snapshots: emoji-regex@9.2.2: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -6606,6 +9471,10 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + + entities@7.0.1: {} + env-paths@2.2.1: {} error-ex@1.3.4: @@ -6616,6 +9485,8 @@ snapshots: es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: @@ -6629,6 +9500,35 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + escalade@3.2.0: {} eslint-scope@5.1.1: @@ -6636,6 +9536,8 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 + esprima@4.0.1: {} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -6646,6 +9548,10 @@ snapshots: estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} event-target-shim@5.0.1: @@ -6655,6 +9561,10 @@ snapshots: eventsource@2.0.2: {} + expect-type@1.3.0: {} + + exsolve@1.0.8: {} + extend@3.0.2: optional: true @@ -6805,6 +9715,10 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-tsconfig@4.13.6: + dependencies: + resolve-pkg-maps: 1.0.0 + git-raw-commits@4.0.0: dependencies: dargs: 8.1.0 @@ -6834,6 +9748,12 @@ snapshots: dependencies: ini: 4.1.1 + globrex@0.1.2: {} + + goober@2.1.18(csstype@3.2.3): + dependencies: + csstype: 3.2.3 + google-auth-library@9.15.1: dependencies: base64-js: 1.5.1 @@ -6882,6 +9802,13 @@ snapshots: - supports-color optional: true + h3@2.0.1-rc.14(crossws@0.4.4(srvx@0.11.4)): + dependencies: + rou3: 0.7.12 + srvx: 0.11.4 + optionalDependencies: + crossws: 0.4.4(srvx@0.11.4) + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -6894,9 +9821,24 @@ snapshots: dependencies: function-bind: 1.1.2 + hookable@6.0.1: {} + + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.14.1 + transitivePeerDependencies: + - '@noble/hashes' + html-entities@2.6.0: optional: true + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 + htmlparser2@8.0.2: dependencies: domelementtype: 2.3.0 @@ -6915,6 +9857,13 @@ snapshots: - supports-color optional: true + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -6928,10 +9877,13 @@ snapshots: debug: 4.4.3 transitivePeerDependencies: - supports-color - optional: true husky@9.1.7: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -6976,6 +9928,8 @@ snapshots: is-obj@2.0.0: {} + is-potential-custom-element-name@1.0.1: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -6987,6 +9941,8 @@ snapshots: dependencies: text-extensions: 2.4.0 + isbot@5.1.35: {} + isexe@2.0.0: {} jackspeak@3.4.3: @@ -7009,10 +9965,40 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.1: {} + js-yaml@4.1.1: dependencies: argparse: 2.0.1 + jsdom@27.4.0: + dependencies: + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.7.8 + '@exodus/bytes': 1.14.1 + cssstyle: 5.3.7 + data-urls: 6.0.1 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + ws: 8.19.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + - bufferutil + - supports-color + - utf-8-validate + jsesc@3.1.0: {} json-bigint@1.0.0: @@ -7064,6 +10050,60 @@ snapshots: kdbush@4.0.2: {} + launch-editor@2.12.0: + dependencies: + picocolors: 1.1.1 + shell-quote: 1.8.3 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + lilconfig@3.1.3: {} limiter@1.1.5: {} @@ -7128,12 +10168,16 @@ snapshots: dependencies: js-tokens: 4.0.0 + loupe@3.2.1: {} + lower-case@2.0.2: dependencies: tslib: 2.8.1 lru-cache@10.4.3: {} + lru-cache@11.2.6: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -7151,6 +10195,12 @@ snapshots: dependencies: react: 18.3.1 + lucide-react@0.561.0(react@19.2.4): + dependencies: + react: 19.2.4 + + lz-string@1.5.0: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -7165,6 +10215,8 @@ snapshots: mdn-data@2.0.30: {} + mdn-data@2.12.2: {} + meow@12.1.1: {} merge-stream@2.0.0: {} @@ -7241,6 +10293,56 @@ snapshots: - '@babel/core' - babel-plugin-macros + nf3@0.3.10: {} + + nitro-nightly@3.0.1-20260213-154614-f663e76d(chokidar@3.6.0)(dotenv@16.6.1)(jiti@2.6.1)(lru-cache@10.4.3)(rollup@4.55.1)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + consola: 3.4.2 + crossws: 0.4.4(srvx@0.11.4) + db0: 0.3.4 + h3: 2.0.1-rc.14(crossws@0.4.4(srvx@0.11.4)) + hookable: 6.0.1 + nf3: 0.3.10 + ofetch: 2.0.0-alpha.3 + ohash: 2.0.11 + rolldown: 1.0.0-rc.4 + srvx: 0.11.4 + unenv: 2.0.0-rc.24 + unstorage: 2.0.0-alpha.5(chokidar@3.6.0)(db0@0.3.4)(lru-cache@10.4.3)(ofetch@2.0.0-alpha.3) + optionalDependencies: + dotenv: 16.6.1 + jiti: 2.6.1 + rollup: 4.55.1 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - better-sqlite3 + - chokidar + - drizzle-orm + - idb-keyval + - ioredis + - lru-cache + - mongodb + - mysql2 + - sqlite3 + - uploadthing + no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -7264,6 +10366,10 @@ snapshots: object-hash@3.0.0: {} + ofetch@2.0.0-alpha.3: {} + + ohash@2.0.11: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -7298,6 +10404,23 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + parse5@8.0.0: + dependencies: + entities: 6.0.1 + path-exists@4.0.0: {} path-exists@5.0.0: {} @@ -7313,6 +10436,10 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + + pathval@2.0.1: {} + pg-int8@1.0.1: {} pg-protocol@1.11.0: {} @@ -7347,12 +10474,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.6 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.6 + tsx: 4.21.0 yaml: 2.8.2 postcss-media-query-parser@0.2.3: {} @@ -7391,6 +10519,14 @@ snapshots: dependencies: xtend: 4.0.2 + prettier@3.8.1: {} + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + progress@2.0.3: {} proto3-json-serializer@2.0.2: @@ -7416,6 +10552,8 @@ snapshots: proxy-from-env@1.1.0: {} + punycode@2.3.1: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -7430,10 +10568,19 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + react-hook-form@7.71.1(react@18.3.1): dependencies: react: 18.3.1 + react-is@17.0.2: {} + + react-refresh@0.18.0: {} + react-remove-scroll-bar@2.3.8(@types/react@18.3.27)(react@18.3.1): dependencies: react: 18.3.1 @@ -7465,6 +10612,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + react@19.2.4: {} + read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -7480,6 +10629,14 @@ snapshots: dependencies: picomatch: 2.3.1 + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + regenerate-unicode-properties@10.2.2: dependencies: regenerate: 1.4.2 @@ -7518,6 +10675,8 @@ snapshots: resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.11: dependencies: is-core-module: 2.16.1 @@ -7539,6 +10698,25 @@ snapshots: reusify@1.1.0: {} + rolldown@1.0.0-rc.4: + dependencies: + '@oxc-project/types': 0.113.0 + '@rolldown/pluginutils': 1.0.0-rc.4 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.4 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.4 + '@rolldown/binding-darwin-x64': 1.0.0-rc.4 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.4 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.4 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.4 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.4 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.4 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.4 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.4 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.4 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.4 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.4 + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 @@ -7570,16 +10748,26 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 + rou3@0.7.12: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 + scheduler@0.27.0: {} + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 @@ -7595,12 +10783,22 @@ snapshots: dependencies: randombytes: 2.1.0 + seroval-plugins@1.5.0(seroval@1.5.0): + dependencies: + seroval: 1.5.0 + + seroval@1.5.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + shell-quote@1.8.3: {} + + siginfo@2.0.0: {} + signal-exit@4.1.0: {} snake-case@3.0.4: @@ -7618,6 +10816,17 @@ snapshots: transitivePeerDependencies: - supports-color + solid-js@1.9.11: + dependencies: + csstype: 3.2.3 + seroval: 1.5.0 + seroval-plugins: 1.5.0(seroval@1.5.0) + + sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -7627,12 +10836,20 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + split2@4.2.0: {} + srvx@0.11.4: {} + + stackback@0.0.2: {} + stacktrace-parser@0.1.11: dependencies: type-fest: 0.7.1 + std-env@3.10.0: {} + stream-events@1.0.5: dependencies: stubs: 3.0.0 @@ -7668,6 +10885,10 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + strnum@1.1.2: optional: true @@ -7717,13 +10938,15 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 + symbol-tree@3.2.4: {} + tailwind-merge@3.4.0: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.19(yaml@2.8.2)): + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)): dependencies: - tailwindcss: 3.4.19(yaml@2.8.2) + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) - tailwindcss@3.4.19(yaml@2.8.2): + tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -7742,7 +10965,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -7751,6 +10974,8 @@ snapshots: - tsx - yaml + tailwindcss@4.1.18: {} + tapable@2.3.0: {} teeny-request@9.0.0: @@ -7795,6 +11020,14 @@ snapshots: through@2.3.8: {} + tiny-invariant@1.3.3: {} + + tiny-warning@1.0.3: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -7802,16 +11035,47 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + tldts-core@7.0.23: {} + + tldts@7.0.23: + dependencies: + tldts-core: 7.0.23 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tough-cookie@6.0.0: + dependencies: + tldts: 7.0.23 + tr46@0.0.3: {} + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + ts-interface-checker@0.1.13: {} + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + tslib@2.8.1: {} + tsx@4.21.0: + dependencies: + esbuild: 0.27.3 + get-tsconfig: 4.13.6 + optionalDependencies: + fsevents: 2.3.3 + turbo-darwin-64@2.7.5: optional: true @@ -7843,8 +11107,16 @@ snapshots: typescript@5.9.3: {} + ufo@1.6.3: {} + undici-types@6.21.0: {} + undici@7.22.0: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -7865,6 +11137,20 @@ snapshots: webpack-sources: 3.3.3 webpack-virtual-modules: 0.5.0 + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + unstorage@2.0.0-alpha.5(chokidar@3.6.0)(db0@0.3.4)(lru-cache@10.4.3)(ofetch@2.0.0-alpha.3): + optionalDependencies: + chokidar: 3.6.0 + db0: 0.3.4 + lru-cache: 10.4.3 + ofetch: 2.0.0-alpha.3 + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -7891,6 +11177,15 @@ snapshots: optionalDependencies: '@types/react': 18.3.27 + use-sync-external-store@1.6.0(react@18.3.1): + dependencies: + react: 18.3.1 + optional: true + + use-sync-external-store@1.6.0(react@19.2.4): + dependencies: + react: 19.2.4 + util-deprecate@1.0.2: {} uuid@10.0.0: {} @@ -7900,17 +11195,121 @@ snapshots: uuid@9.0.1: {} + vite-node@3.2.4(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + debug: 4.4.3 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.3) + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + - typescript + + vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.55.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.19.7 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + terser: 5.46.0 + tsx: 4.21.0 + yaml: 2.8.2 + + vitefu@1.1.1(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): + optionalDependencies: + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + + vitest@3.2.4(@types/node@22.19.7)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.19.7 + jsdom: 27.4.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + web-vitals@5.1.0: {} + webidl-conversions@3.0.1: {} + webidl-conversions@8.0.1: {} + webpack-sources@3.3.3: {} webpack-virtual-modules@0.5.0: {} + webpack-virtual-modules@0.6.2: {} + webpack@5.104.1: dependencies: '@types/eslint-scope': 3.7.7 @@ -7951,6 +11350,19 @@ snapshots: websocket-extensions@0.1.4: {} + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@15.1.0: + dependencies: + tr46: 6.0.0 + webidl-conversions: 8.0.1 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -7960,6 +11372,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -7975,6 +11392,19 @@ snapshots: wrappy@1.0.2: optional: true + ws@8.19.0: {} + + xml-name-validator@5.0.0: {} + + xmlbuilder2@4.0.3: + dependencies: + '@oozcitak/dom': 2.0.2 + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + js-yaml: 4.1.1 + + xmlchars@2.2.0: {} + xtend@4.0.2: {} y18n@5.0.8: {} @@ -8001,9 +11431,12 @@ snapshots: yocto-queue@1.2.2: {} + zod@3.25.76: {} + zod@4.3.6: {} - zustand@5.0.10(@types/react@18.3.27)(react@18.3.1): + zustand@5.0.10(@types/react@18.3.27)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): optionalDependencies: '@types/react': 18.3.27 react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1)