diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7884d7b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +# Matches multiple files with brace expansion notation +[*.{js,jsx,ts,tsx,json,css,scss,yml,yaml}] +indent_size = 2 + +# Markdown files +[*.md] +trim_trailing_whitespace = false + +# Package files +[package.json] +indent_size = 2 + +# YAML files +[*.{yml,yaml}] +indent_size = 2 + +# Makefile +[Makefile] +indent_style = tab \ No newline at end of file diff --git a/.env.example b/.env.example index fd4515f..68aaaf2 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,73 @@ -# Base64 Encoded Service Account JSON +# ================================================================ +# Application Configuration +# ================================================================ +# Node environment: development, production, test +NODE_ENV=development + +# ================================================================ +# Next.js Configuration +# ================================================================ +# Public URL of your application +NEXT_PUBLIC_APP_URL=http://localhost:3000 + +# API URL (if different from app URL) +NEXT_PUBLIC_API_URL=http://localhost:3000/api + +# Site name for SEO and metadata +NEXT_PUBLIC_SITE_NAME="Next.js App" + +# ================================================================ +# Google Drive Configuration +# ================================================================ +# Base64 encoded service account credentials GD_SERVICE_B64= -# Secret Key for Encryption + +# Encryption key for secure operations ENCRYPTION_KEY= + +# ================================================================ +# Database Configuration (if applicable) +# ================================================================ +# DATABASE_URL=postgresql://user:password@localhost:5432/dbname + +# ================================================================ +# Authentication (if applicable) +# ================================================================ +# JWT_SECRET= +# AUTH_SECRET= + +# ================================================================ +# External Services (if applicable) +# ================================================================ +# Analytics +# NEXT_PUBLIC_GOOGLE_ANALYTICS_ID= +# NEXT_PUBLIC_MIXPANEL_TOKEN= + +# Error Tracking +# SENTRY_DSN= +# NEXT_PUBLIC_SENTRY_DSN= + +# Email Service +# SMTP_HOST= +# SMTP_PORT= +# SMTP_USER= +# SMTP_PASSWORD= + +# ================================================================ +# Feature Flags (if applicable) +# ================================================================ +# NEXT_PUBLIC_ENABLE_FEATURE_X=false +# NEXT_PUBLIC_ENABLE_BETA_FEATURES=false + +# ================================================================ +# Development Tools +# ================================================================ +# Enable debug logging +# DEBUG=true + +# Disable Next.js telemetry +NEXT_TELEMETRY_DISABLED=1 + # Index password, used when private mode is enabled SITE_PASSWORD= diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..165afde --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ +## Description + +Please include a summary of the changes and which issue is fixed. Include relevant motivation and context. + +Fixes # (issue) + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Performance improvement +- [ ] Code refactoring + +## Checklist + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published + +## Screenshots (if applicable) + +Please add screenshots to help explain your changes. + +## Additional context + +Add any other context about the pull request here. \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..674c072 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,161 @@ +name: CI + +on: + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + +env: + NODE_VERSION: "20.x" + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + run: npm run lint + + - name: Check Prettier formatting + run: npm run format:check + + type-check: + name: Type Check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Run TypeScript type check + run: npm run type-check + + build: + name: Build + runs-on: ubuntu-latest + needs: [lint, type-check] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Build application + run: npm run build + env: + NEXT_TELEMETRY_DISABLED: 1 + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: .next + retention-days: 7 + + test: + name: Test + runs-on: ubuntu-latest + needs: [lint, type-check] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "npm" + + - name: Install dependencies + run: npm ci + + # Uncomment when tests are added + # - name: Run unit tests + # run: npm test + + # - name: Run integration tests + # run: npm run test:integration + + # - name: Upload coverage reports + # uses: codecov/codecov-action@v4 + # with: + # file: ./coverage/coverage-final.json + # flags: unittests + # name: codecov-umbrella + + security: + name: Security Scan + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run npm audit + run: npm audit --audit-level=high + continue-on-error: true + + - name: Run Snyk to check for vulnerabilities + uses: snyk/actions/node@master + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + lighthouse: + name: Lighthouse CI + runs-on: ubuntu-latest + needs: build + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-artifacts + path: .next + + - name: Run Lighthouse CI + uses: treosh/lighthouse-ci-action@v12 + with: + urls: | + http://localhost:3000 + uploadArtifacts: true + temporaryPublicStorage: true + continue-on-error: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..e24984e --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,40 @@ +name: CodeQL + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + schedule: + - cron: "0 0 * * 1" # Weekly on Monday + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["javascript", "typescript"] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..7ad8866 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,19 @@ +name: Dependency Review + +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + name: Dependency Review + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v4 + with: + fail-on-severity: moderate diff --git a/.gitignore b/.gitignore index 50d3ab5..e2b839c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,47 +1,246 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring file. -# dependencies -/node_modules -/.pnp +# ================================================================ +# Dependencies +# ================================================================ +node_modules/ +.pnp .pnp.js +.yarn/install-state.gz -# testing -/coverage +# ================================================================ +# Build Outputs & Caches +# ================================================================ +# Next.js +.next/ +out/ +build/ +dist/ -# next.js -/out/ +# Vercel +.vercel -# production -/build +# TypeScript +*.tsbuildinfo +next-env.d.ts + +# Parcel +.cache +.parcel-cache + +# Webpack +.webpack/ + +# ================================================================ +# Environment Variables +# ================================================================ +.env +.env.local +.env.development +.env.development.local +.env.test +.env.test.local +.env.production +.env.production.local + +# ================================================================ +# Logs & Debug Files +# ================================================================ +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* -# misc +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# ================================================================ +# Testing & Coverage +# ================================================================ +coverage/ +.nyc_output/ +test-results/ +playwright-report/ +playwright/.cache/ +vitest.config.*.timestamp-* + +# ================================================================ +# OS Generated Files +# ================================================================ +# macOS .DS_Store -*.pem +.AppleDouble +.LSOverride +._* +.Spotlight-V100 +.Trashes + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ +*.lnk + +# Linux +.directory +*~ + +# ================================================================ +# Editor & IDE Files +# ================================================================ +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/extensions.json +!.vscode/launch.json +!.vscode/tasks.json +*.code-workspace -# debug +# IntelliJ IDEA / WebStorm +.idea/ +*.iml +*.iws +*.ipr + +# Sublime Text +*.sublime-project +*.sublime-workspace + +# Vim +*.swp +*.swo +*.swn +.vim/ +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +Session.vim +tags + +# Emacs +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# ================================================================ +# Package Managers +# ================================================================ +# npm npm-debug.log* +.npm + +# Yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions yarn-debug.log* yarn-error.log* -# local env file -.env -.env.local +# pnpm +pnpm-debug.log* -# typescript -*.tsbuildinfo -next-env.d.ts +# ================================================================ +# Security & Certificates +# ================================================================ +*.pem +*.key +*.crt +*.p12 +*.pfx + +# ================================================================ +# Temporary Files +# ================================================================ +tmp/ +temp/ +*.tmp +*.temp +*.bak +*.backup +*.old + +# ================================================================ +# Miscellaneous +# ================================================================ +# Prettier cache +.prettierignore_cache +.prettiercache + +# ESLint cache +.eslintcache + +# Stylelint cache +.stylelintcache + +# Serverless +.serverless/ + +# FuseBox +.fusebox/ + +# DynamoDB Local +.dynamodb/ -# personal docs +# TernJS +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# ================================================================ +# Project Specific Exclusions +# ================================================================ +# Documentation (if private) /docs +/private-docs + +# Legacy code /src/pages/api/legacy/ /**/*/_legacy/ -# /**/*/_*/ -/data -/.*/ /src/_app /src/_page /src/utils/_legacy /src/components/_legacy -.env.production -!.cursor/ +# Data files +/data + +# Hidden directories (except specific ones) +/.* +!/.github +!/.husky +!/.vscode +!/.cursor +!/.env.example +!/.lintstagedrc.json +!/.editorconfig +!/.prettierrc +!/.prettierignore + +# Build analysis +.next/analyze/ +bundle-analyzer/ + +# Storybook +storybook-static/ + +# Sentry +.sentryclirc + +# PWA +public/sw.js +public/workbox-*.js +public/worker-*.js +public/fallback-*.js +public/precache.*.js \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..990bd0b --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit "$1" \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..2312dc5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..5da8a12 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1 @@ +npm run validate \ No newline at end of file diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..45829ab --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"], + "*.{json,md,mdx,css,html,yml,yaml,scss}": ["prettier --write"] +} diff --git a/.prettierignore b/.prettierignore index 1b8ac88..10aa957 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,83 @@ -# Ignore artifacts: +# ================================================================ +# Dependencies & Package Files +# ================================================================ +node_modules +package-lock.json +yarn.lock +pnpm-lock.yaml +.yarn + +# ================================================================ +# Build Outputs +# ================================================================ +.next +out build +dist coverage +.vercel +storybook-static + +# ================================================================ +# Version Control +# ================================================================ +.git +.husky/_ + +# ================================================================ +# IDE & Editor Files +# ================================================================ +.vscode +.idea + +# ================================================================ +# Documentation +# ================================================================ +*.md +LICENSE +CHANGELOG + +# ================================================================ +# Data & Large Files +# ================================================================ +*.csv +*.sql +*.db +*.sqlite + +# ================================================================ +# Generated Files +# ================================================================ +*.min.js +*.min.css +public/sw.js +public/workbox-*.js +public/worker-*.js +public/fallback-*.js +public/precache.*.js + +# ================================================================ +# Temporary Files +# ================================================================ +*.log +*.tmp +*.temp +.cache +.parcel-cache + +# ================================================================ +# Environment Files +# ================================================================ +.env* + +# ================================================================ +# TypeScript Files +# ================================================================ +*.tsbuildinfo +*.d.ts + +# ================================================================ +# Other Files to Skip +# ================================================================ +.DS_Store +Thumbs.db diff --git a/.prettierrc b/.prettierrc index 9e26dfe..cce4fd7 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1 +1,14 @@ -{} \ No newline at end of file +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": false, + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "lf", + "proseWrap": "preserve", + "quoteProps": "as-needed", + "bracketSameLine": false +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..19b8a79 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,12 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "bradlc.vscode-tailwindcss", + "naumovs.color-highlight", + "usernamehw.errorlens", + "wix.vscode-import-cost", + "formulahendry.auto-rename-tag", + "yoavbls.pretty-ts-errors" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d3247ff --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,43 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "never" + }, + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true, + "files.associations": { + "*.css": "tailwindcss" + }, + "tailwindCSS.experimental.classRegex": [ + ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], + ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] + ], + "git.enableSmartCommit": true, + "git.autofetch": true, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} \ No newline at end of file diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..d51ed31 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,32 @@ +export default { + extends: ["@commitlint/config-conventional"], + rules: { + "type-enum": [ + 2, + "always", + [ + "feat", // New feature + "fix", // Bug fix + "docs", // Documentation only changes + "style", // Changes that do not affect the meaning of the code + "refactor", // Code change that neither fixes a bug nor adds a feature + "perf", // Performance improvements + "test", // Adding missing tests or correcting existing tests + "build", // Changes that affect the build system or external dependencies + "ci", // Changes to CI configuration files and scripts + "chore", // Other changes that don't modify src or test files + "revert", // Reverts a previous commit + ], + ], + "subject-case": [ + 2, + "never", + ["sentence-case", "start-case", "pascal-case", "upper-case"], + ], + "subject-empty": [2, "never"], + "type-case": [2, "always", "lower-case"], + "type-empty": [2, "never"], + "header-max-length": [2, "always", 100], + "body-max-line-length": [2, "always", 500], + }, +}; diff --git a/eslint.config.mjs b/eslint.config.mjs index b879b63..b7531cf 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,13 +1,157 @@ +import js from "@eslint/js"; import { FlatCompat } from "@eslint/eslintrc"; const compat = new FlatCompat({ + // import.meta.dirname is available after Node.js v20.11.0 baseDirectory: import.meta.dirname, + recommendedConfig: js.configs.recommended, }); const eslintConfig = [ + // Use Next.js recommended configuration as base ...compat.config({ - extends: ["next/core-web-vitals", "next/typescript", "prettier"], + extends: [ + "next/core-web-vitals", // Includes Next.js specific rules + React rules + "next/typescript", // TypeScript specific rules for Next.js + "prettier", // Disable ESLint rules that conflict with Prettier + ], }), + // Global ignores (replaces .eslintignore) + { + ignores: [ + // Dependencies + "**/node_modules/**", + "**/.pnp", + "**/.pnp.js", + "**/.yarn/**", + + // Build outputs + "**/.next/**", + "**/out/**", + "**/build/**", + "**/dist/**", + "**/.vercel/**", + "**/storybook-static/**", + + // Testing & Coverage + "**/coverage/**", + "**/.nyc_output/**", + "**/test-results/**", + "**/playwright-report/**", + "**/playwright/.cache/**", + + // Configuration files + "**/*.config.js", + "**/*.config.mjs", + "**/*.config.ts", + "**/commitlint.config.js", + + // Generated files + "**/*.min.js", + "**/*.min.css", + "**/public/sw.js", + "**/public/workbox-*.js", + "**/public/worker-*.js", + "**/public/fallback-*.js", + "**/public/precache.*.js", + + // TypeScript + "**/*.d.ts", + "**/next-env.d.ts", + "**/*.tsbuildinfo", + + // Logs + "**/logs/**", + "**/*.log", + "**/npm-debug.log*", + "**/yarn-debug.log*", + "**/yarn-error.log*", + "**/pnpm-debug.log*", + "**/lerna-debug.log*", + + // OS files + "**/.DS_Store", + "**/Thumbs.db", + + // Security + "**/*.pem", + "**/*.key", + "**/*.crt", + + // Environment + "**/.env*", + + // Temporary & cache + "**/.cache/**", + "**/.parcel-cache/**", + "**/tmp/**", + "**/temp/**", + "**/*.tmp", + "**/*.temp", + + // Package files + "**/package-lock.json", + "**/yarn.lock", + "**/pnpm-lock.yaml", + + // Documentation + "**/*.md", + "**/LICENSE", + + // Misc + "**/.eslintcache", + "**/.prettierignore", + "**/.gitignore", + ], + }, + // Add custom rules as a separate configuration object + { + rules: { + // TypeScript rules (warnings for gradual adoption) + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "@typescript-eslint/consistent-type-imports": [ + "warn", + { + prefer: "type-imports", + fixStyle: "inline-type-imports", + }, + ], + + // React best practices + // Allow both arrow functions and function declarations + "react/function-component-definition": "off", + + // Next.js specific rules + "@next/next/no-html-link-for-pages": "error", + "@next/next/no-img-element": "warn", // Warn instead of error for gradual migration + + // General code quality + "no-console": [ + "warn", + { + allow: ["warn", "error", "info", "debug"], // Allow more console methods in development + }, + ], + "prefer-const": "error", + "no-var": "error", + "object-shorthand": "warn", + "prefer-arrow-callback": "off", // Turn off to allow function expressions + "prefer-template": "warn", + + // Import rules (when import plugin is available) + "import/first": "off", + "import/newline-after-import": "off", + "import/no-duplicates": "off", + }, + }, ]; export default eslintConfig; diff --git a/next.config.ts b/next.config.ts index 1f08995..92e889a 100644 --- a/next.config.ts +++ b/next.config.ts @@ -2,7 +2,7 @@ import type { NextConfig } from "next"; /** * Production-ready Next.js configuration optimized for Google Drive Index applications - * + * * Key optimizations: * - Google Drive API caching and rate limiting * - Large file streaming and thumbnail optimization @@ -15,44 +15,44 @@ const nextConfig: NextConfig = { // Basic Configuration reactStrictMode: true, pageExtensions: ["tsx", "ts"], - + // Performance Optimizations poweredByHeader: false, generateEtags: true, - + // Cloudflare Workers Optimization - output: 'standalone', - + output: "standalone", + // Performance Monitoring experimental: { optimizePackageImports: [ - '@radix-ui/react-icons', - '@radix-ui/react-dialog', - '@radix-ui/react-dropdown-menu', - '@radix-ui/react-popover', - '@radix-ui/react-select', - '@radix-ui/react-tooltip', - 'lucide-react', - 'date-fns', - 'react-markdown', - 'framer-motion', - '@tanstack/react-virtual', + "@radix-ui/react-icons", + "@radix-ui/react-dialog", + "@radix-ui/react-dropdown-menu", + "@radix-ui/react-popover", + "@radix-ui/react-select", + "@radix-ui/react-tooltip", + "lucide-react", + "date-fns", + "react-markdown", + "framer-motion", + "@tanstack/react-virtual", ], nodeMiddleware: true, // Server Actions optimization for Google Drive API serverActions: { - allowedOrigins: ['localhost:3000', process.env.VERCEL_URL || ''], - bodySizeLimit: '10mb', // Large file metadata + allowedOrigins: ["localhost:3000", process.env.VERCEL_URL || ""], + bodySizeLimit: "10mb", // Large file metadata }, // Optimize for file serving optimizeServerReact: true, // Experimental performance features - webVitalsAttribution: ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'], + webVitalsAttribution: ["CLS", "FCP", "FID", "INP", "LCP", "TTFB"], }, - + // Image Optimization (Google Drive + Cloudflare optimized) images: { - formats: ['image/avif', 'image/webp'], + formats: ["image/avif", "image/webp"], deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], minimumCacheTTL: 31536000, // 1 year @@ -61,167 +61,168 @@ const nextConfig: NextConfig = { // Google Drive thumbnails and external domains remotePatterns: [ { - protocol: 'https', - hostname: 'drive.google.com', - pathname: '/thumbnail**', + protocol: "https", + hostname: "drive.google.com", + pathname: "/thumbnail**", }, { - protocol: 'https', - hostname: 'lh3.googleusercontent.com', - pathname: '**', + protocol: "https", + hostname: "lh3.googleusercontent.com", + pathname: "**", }, { - protocol: 'https', - hostname: 'docs.google.com', - pathname: '**', + protocol: "https", + hostname: "docs.google.com", + pathname: "**", }, ], unoptimized: false, }, - + // Bundle Optimization - + // Turbopack Configuration (Next.js 15+) turbopack: { - resolveExtensions: [ - '.mdx', - '.tsx', - '.ts', - '.jsx', - '.js', - '.mjs', - '.json', - ], + resolveExtensions: [".mdx", ".tsx", ".ts", ".jsx", ".js", ".mjs", ".json"], }, - + // Compiler Optimizations compiler: { - removeConsole: process.env.NODE_ENV === 'production' ? { - exclude: ['error', 'warn'], - } : false, + removeConsole: + process.env.NODE_ENV === "production" + ? { + exclude: ["error", "warn"], + } + : false, // React compiler optimization (if available) - reactRemoveProperties: process.env.NODE_ENV === 'production' ? { - properties: ['^data-testid$'] - } : false, + reactRemoveProperties: + process.env.NODE_ENV === "production" + ? { + properties: ["^data-testid$"], + } + : false, }, - + // Security Headers + Google Drive Optimization async headers() { return [ { - source: '/(.*)', + source: "/(.*)", headers: [ { - key: 'X-Frame-Options', - value: 'DENY', + key: "X-Frame-Options", + value: "DENY", }, { - key: 'X-Content-Type-Options', - value: 'nosniff', + key: "X-Content-Type-Options", + value: "nosniff", }, { - key: 'X-XSS-Protection', - value: '1; mode=block', + key: "X-XSS-Protection", + value: "1; mode=block", }, { - key: 'Referrer-Policy', - value: 'strict-origin-when-cross-origin', + key: "Referrer-Policy", + value: "strict-origin-when-cross-origin", }, { - key: 'Permissions-Policy', - value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()', + key: "Permissions-Policy", + value: + "camera=(), microphone=(), geolocation=(), browsing-topics=()", }, ], }, // Google Drive API routes - Short cache with background refresh { - source: '/api/(files|search|paths)/(.*)', + source: "/api/(files|search|paths)/(.*)", headers: [ { - key: 'Cache-Control', - value: 'public, s-maxage=300, stale-while-revalidate=900', // 5min cache, 15min stale + key: "Cache-Control", + value: "public, s-maxage=300, stale-while-revalidate=900", // 5min cache, 15min stale }, ], }, // File downloads - Long cache for immutable content { - source: '/api/(download|raw)/(.*)', + source: "/api/(download|raw)/(.*)", headers: [ { - key: 'Cache-Control', - value: 'public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800', // 1hr, 1day, 1week + key: "Cache-Control", + value: + "public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800", // 1hr, 1day, 1week }, { - key: 'X-Content-Type-Options', - value: 'nosniff', + key: "X-Content-Type-Options", + value: "nosniff", }, ], }, // Thumbnails - Very long cache { - source: '/api/(thumb|og)/(.*)', + source: "/api/(thumb|og)/(.*)", headers: [ { - key: 'Cache-Control', - value: 'public, max-age=2592000, s-maxage=31536000, immutable', // 30days, 1year + key: "Cache-Control", + value: "public, max-age=2592000, s-maxage=31536000, immutable", // 30days, 1year }, ], }, // Other API routes { - source: '/api/(.*)', + source: "/api/(.*)", headers: [ { - key: 'Cache-Control', - value: 'public, s-maxage=60, stale-while-revalidate=300', // 1min cache, 5min stale + key: "Cache-Control", + value: "public, s-maxage=60, stale-while-revalidate=300", // 1min cache, 5min stale }, ], }, // Static assets { - source: '/(_next/static/.*|favicon.ico|favicon.png|favicon.svg|logo.svg)', + source: + "/(_next/static/.*|favicon.ico|favicon.png|favicon.svg|logo.svg)", headers: [ { - key: 'Cache-Control', - value: 'public, max-age=31536000, immutable', + key: "Cache-Control", + value: "public, max-age=31536000, immutable", }, ], }, ]; }, - + // Webpack Configuration webpack: (config, { dev, isServer }) => { // Optimize bundle size config.optimization = { ...config.optimization, splitChunks: { - chunks: 'all', + chunks: "all", cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, - name: 'vendors', + name: "vendors", priority: 10, reuseExistingChunk: true, }, // Google APIs and Drive-specific libraries googleapis: { test: /[\\/]node_modules[\\/](googleapis|@google-cloud)[\\/]/, - name: 'googleapis', + name: "googleapis", priority: 15, reuseExistingChunk: true, }, // Media handling libraries media: { test: /[\\/]node_modules[\\/](fflate|@vidstack)[\\/]/, - name: 'media', + name: "media", priority: 12, reuseExistingChunk: true, }, // UI components ui: { test: /[\\/]node_modules[\\/](@radix-ui|lucide-react)[\\/]/, - name: 'ui', + name: "ui", priority: 11, reuseExistingChunk: true, }, @@ -233,12 +234,12 @@ const nextConfig: NextConfig = { }, }, }; - + // Performance monitoring in development if (dev && !isServer) { config.optimization.concatenateModules = false; // Better for debugging } - + // Optimize for large file handling config.resolve.fallback = { ...config.resolve.fallback, @@ -246,60 +247,61 @@ const nextConfig: NextConfig = { net: false, tls: false, }; - + return config; }, - + // TypeScript Configuration typescript: { ignoreBuildErrors: false, }, - + // ESLint Configuration eslint: { ignoreDuringBuilds: false, }, - + // Redirects for better SEO and UX async redirects() { return [ { - source: '/home', - destination: '/', + source: "/home", + destination: "/", permanent: true, }, // Legacy Google Drive URLs redirect { - source: '/drive/:path*', - destination: '/:path*', + source: "/drive/:path*", + destination: "/:path*", permanent: true, }, // File viewer redirect (common pattern) { - source: '/file/:path*', - destination: '/:path*', + source: "/file/:path*", + destination: "/:path*", permanent: true, }, - // Directory listing redirect + // Directory listing redirect { - source: '/folder/:path*', - destination: '/:path*', + source: "/folder/:path*", + destination: "/:path*", permanent: true, }, ]; }, - + // Environment Variables env: { - CUSTOM_KEY: process.env.CUSTOM_KEY || '', + CUSTOM_KEY: process.env.CUSTOM_KEY || "", // Google Drive API optimization - GOOGLE_DRIVE_API_TIMEOUT: process.env.GOOGLE_DRIVE_API_TIMEOUT || '30000', + GOOGLE_DRIVE_API_TIMEOUT: process.env.GOOGLE_DRIVE_API_TIMEOUT || "30000", // Enable streaming for large files - ENABLE_FILE_STREAMING: process.env.ENABLE_FILE_STREAMING || 'true', + ENABLE_FILE_STREAMING: process.env.ENABLE_FILE_STREAMING || "true", // Performance monitoring - ENABLE_PERFORMANCE_MONITORING: process.env.ENABLE_PERFORMANCE_MONITORING || 'false', + ENABLE_PERFORMANCE_MONITORING: + process.env.ENABLE_PERFORMANCE_MONITORING || "false", }, - + // Server-side configuration for Google Drive serverRuntimeConfig: { // Google Drive API connection settings @@ -307,18 +309,18 @@ const nextConfig: NextConfig = { maxFileSize: 100 * 1024 * 1024, // 100MB default chunkSize: 1024 * 1024, // 1MB chunks for streaming }, - + // Public runtime config publicRuntimeConfig: { // Cache settings for client-side thumbnailCacheTTL: 3600000, // 1 hour - fileListCacheTTL: 300000, // 5 minutes + fileListCacheTTL: 300000, // 5 minutes // Performance monitoring - performanceMonitoring: process.env.ENABLE_PERFORMANCE_MONITORING === 'true', + performanceMonitoring: process.env.ENABLE_PERFORMANCE_MONITORING === "true", }, - + // Development Configuration - ...(process.env.NODE_ENV === 'development' && { + ...(process.env.NODE_ENV === "development" && { onDemandEntries: { maxInactiveAge: 25 * 1000, pagesBufferLength: 2, diff --git a/package-lock.json b/package-lock.json index 61cdfd7..64b9a9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,8 +77,11 @@ "zod": "^3.25.74" }, "devDependencies": { + "@commitlint/cli": "^19.8.1", + "@commitlint/config-conventional": "^19.8.1", + "@eslint/js": "^9.30.1", + "@next/eslint-plugin-next": "^15.3.5", "@tailwindcss/postcss": "^4.1.11", - "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@types/cors": "^2.8.19", "@types/eslint": "^9.6.1", "@types/mime-types": "^3.0.1", @@ -96,6 +99,13 @@ "eslint": "^9.30.1", "eslint-config-next": "^15.3.5", "eslint-config-prettier": "^10.1.5", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-next": "^0.0.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "husky": "^9.1.7", + "lint-staged": "^16.1.2", "ora": "^8.2.0", "postcss": "^8.5.6", "prettier": "3.6.2", @@ -147,115 +157,271 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@commitlint/cli": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.8.1.tgz", + "integrity": "sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "@commitlint/format": "^19.8.1", + "@commitlint/lint": "^19.8.1", + "@commitlint/load": "^19.8.1", + "@commitlint/read": "^19.8.1", + "@commitlint/types": "^19.8.1", + "tinyexec": "^1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "node_modules/@commitlint/config-conventional": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz", + "integrity": "sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==", "dev": true, "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "node_modules/@commitlint/config-validator": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz", + "integrity": "sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==", "dev": true, "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "ajv": "^8.11.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "node_modules/@commitlint/ensure": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.8.1.tgz", + "integrity": "sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==", "dev": true, "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz", + "integrity": "sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" } }, - "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "node_modules/@commitlint/format": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.8.1.tgz", + "integrity": "sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.0" + "@commitlint/types": "^19.8.1", + "chalk": "^5.3.0" }, - "bin": { - "parser": "bin/babel-parser.js" + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz", + "integrity": "sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "semver": "^7.6.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=v18" } }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@commitlint/lint": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.1.tgz", + "integrity": "sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@commitlint/is-ignored": "^19.8.1", + "@commitlint/parse": "^19.8.1", + "@commitlint/rules": "^19.8.1", + "@commitlint/types": "^19.8.1" }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" } }, - "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "node_modules/@commitlint/load": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.8.1.tgz", + "integrity": "sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", - "debug": "^4.3.1" + "@commitlint/config-validator": "^19.8.1", + "@commitlint/execute-rule": "^19.8.1", + "@commitlint/resolve-extends": "^19.8.1", + "@commitlint/types": "^19.8.1", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" + } + }, + "node_modules/@commitlint/message": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.8.1.tgz", + "integrity": "sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" } }, - "node_modules/@babel/types": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", - "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", + "node_modules/@commitlint/parse": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.8.1.tgz", + "integrity": "sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@commitlint/types": "^19.8.1", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.8.1.tgz", + "integrity": "sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^19.8.1", + "@commitlint/types": "^19.8.1", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz", + "integrity": "sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.8.1", + "@commitlint/types": "^19.8.1", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.8.1.tgz", + "integrity": "sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^19.8.1", + "@commitlint/message": "^19.8.1", + "@commitlint/to-lines": "^19.8.1", + "@commitlint/types": "^19.8.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.8.1.tgz", + "integrity": "sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.8.1.tgz", + "integrity": "sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.8.1.tgz", + "integrity": "sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" } }, "node_modules/@date-fns/tz": { @@ -272,21 +438,21 @@ "license": "Apache-2.0" }, "node_modules/@emnapi/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", - "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.4.tgz", + "integrity": "sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.2", + "@emnapi/wasi-threads": "1.0.3", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.4.tgz", + "integrity": "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==", "license": "MIT", "optional": true, "dependencies": { @@ -294,9 +460,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", - "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.3.tgz", + "integrity": "sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==", "dev": true, "license": "MIT", "optional": true, @@ -419,6 +585,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -440,6 +623,13 @@ "node": ">= 4" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3026,41 +3216,6 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz", - "integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@babel/generator": "^7.26.5", - "@babel/parser": "^7.26.7", - "@babel/traverse": "^7.26.7", - "@babel/types": "^7.26.7", - "javascript-natural-sort": "^0.7.1", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">18.12" - }, - "peerDependencies": { - "@vue/compiler-sfc": "3.x", - "prettier": "2.x - 3.x", - "prettier-plugin-svelte": "3.x", - "svelte": "4.x || 5.x" - }, - "peerDependenciesMeta": { - "@vue/compiler-sfc": { - "optional": true - }, - "prettier-plugin-svelte": { - "optional": true - }, - "svelte": { - "optional": true - } - } - }, "node_modules/@tweenjs/tween.js": { "version": "23.1.3", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", @@ -3079,6 +3234,16 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", + "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cors": { "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", @@ -3188,12 +3353,12 @@ } }, "node_modules/@types/hast": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", - "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { - "@types/unist": "^2" + "@types/unist": "*" } }, "node_modules/@types/json-schema": { @@ -3310,9 +3475,9 @@ "license": "MIT" }, "node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, "node_modules/@types/use-sync-external-store": { @@ -3894,33 +4059,59 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "environment": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -3972,6 +4163,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, "node_modules/array-includes": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", @@ -4373,9 +4571,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001726", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", - "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", "funding": [ { "type": "opencollective", @@ -4506,62 +4704,183 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cmdk": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", - "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", - "license": "MIT", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", "dependencies": { - "@radix-ui/react-compose-refs": "^1.1.1", - "@radix-ui/react-dialog": "^1.1.6", - "@radix-ui/react-id": "^1.1.0", - "@radix-ui/react-primitive": "^2.0.2" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, - "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "react-dom": "^18 || ^19 || ^19.0.0-rc" + "engines": { + "node": ">=12" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, "engines": { - "node": ">=12.5.0" + "node": ">=8" } }, - "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==", - "devOptional": true, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "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/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.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==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { @@ -4582,6 +4901,13 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -4602,6 +4928,17 @@ "node": ">=20" } }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4609,6 +4946,96 @@ "dev": true, "license": "MIT" }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz", + "integrity": "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "^2.4.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4758,6 +5185,19 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", @@ -4954,6 +5394,32 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -5070,6 +5536,39 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-abstract": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", @@ -5522,19 +6021,6 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint-plugin-import/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5612,6 +6098,13 @@ "node": "*" } }, + "node_modules/eslint-plugin-next": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-next/-/eslint-plugin-next-0.0.0.tgz", + "integrity": "sha512-IldNDVb6WNduggwRbYzSGZhaskUwVecJ6fhmqwX01+S1aohwAWNzU4me6y47DDzpD/g0fdayNBGxEdt9vKkUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/eslint-plugin-react": { "version": "7.37.5", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", @@ -5669,19 +6162,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/eslint-plugin-react/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5753,21 +6233,54 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -5794,6 +6307,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5804,6 +6334,29 @@ "node": ">= 4" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5817,6 +6370,61 @@ "node": "*" } }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -5967,6 +6575,23 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -6033,17 +6658,18 @@ } }, "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6207,6 +6833,16 @@ "node": ">=18" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-east-asian-width": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", @@ -6297,6 +6933,24 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", @@ -6316,6 +6970,22 @@ "node": ">=10.13.0" } }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -6548,55 +7218,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-dom/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-from-dom/node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-dom/node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-dom/node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/hast-util-from-html": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", @@ -6631,24 +7252,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-html-isomorphic/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-from-html/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/hast-util-from-parse5": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", @@ -6669,61 +7272,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-from-parse5/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/hast-util-from-parse5/node_modules/hast-util-parse-selector": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", - "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-parse5/node_modules/hastscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", - "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", - "license": "MIT", - "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-from-parse5/node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/hast-util-heading-rank": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", @@ -6737,15 +7285,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-heading-rank/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/hast-util-is-element": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", @@ -6759,22 +7298,13 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-is-element/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/hast-util-parse-selector": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", - "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0" + "@types/hast": "^3.0.0" }, "funding": { "type": "opencollective", @@ -6806,21 +7336,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-raw/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-raw/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", @@ -6848,31 +7363,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", @@ -6892,13 +7382,14 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-parse5/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", "license": "MIT", - "dependencies": { - "@types/unist": "*" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/hast-util-to-string": { @@ -6910,17 +7401,8 @@ "@types/hast": "^3.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-string/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/hast-util-to-text": { @@ -6939,21 +7421,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-text/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-to-text/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -6967,25 +7434,16 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-whitespace/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/hastscript": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", - "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", + "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" }, "funding": { @@ -7026,6 +7484,22 @@ "node": ">= 14" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -7076,6 +7550,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -7086,6 +7581,16 @@ "node": ">=0.8.19" } }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/inline-style-parser": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", @@ -7169,11 +7674,11 @@ } }, "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT", - "optional": true + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" }, "node_modules/is-async-function": { "version": "2.1.1", @@ -7338,6 +7843,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -7446,6 +7964,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -7541,6 +8069,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -7648,13 +8189,6 @@ "node": ">= 0.4" } }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", - "dev": true, - "license": "MIT" - }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -7684,19 +8218,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -7713,10 +8234,17 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -7740,6 +8268,33 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -8095,26 +8650,106 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.2.tgz", + "integrity": "sha512-sQKw2Si2g9KUZNY3XNvRuDq4UJqpHwF0/FQzZR2M7I5MvtpWvibikCjUVJzZdGE0ByurEl3KQNvsGetd1ty1/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0", + "debug": "^4.4.1", + "lilconfig": "^3.1.3", + "listr2": "^8.3.3", + "micromatch": "^4.0.8", + "nano-spawn": "^1.0.2", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", "dev": true, "license": "MIT" }, @@ -8125,6 +8760,41 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", @@ -8155,6 +8825,59 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -8267,12 +8990,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/mdast-util-gfm": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", @@ -8386,20 +9103,11 @@ "longest-streak": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.1.0", - "unist-util-remove-position": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-math/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/mdast-util-mdx-expression": { @@ -8420,15 +9128,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-expression/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-mdx-jsx": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", @@ -8453,21 +9152,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", @@ -8486,15 +9170,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-newline-to-break": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz", @@ -8544,15 +9219,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-hast/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-to-markdown": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", @@ -8574,12 +9240,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/mdast-util-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", @@ -8621,6 +9281,19 @@ "node": ">=16" } }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -9333,6 +10006,19 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/nano-spawn": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.2.tgz", + "integrity": "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -9722,35 +10408,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/own-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", @@ -9770,32 +10427,32 @@ } }, "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -9833,6 +10490,31 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-numeric-range": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", @@ -9852,13 +10534,13 @@ } }, "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/path-key": { @@ -9897,6 +10579,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -9994,10 +10689,16 @@ "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", "funding": { "type": "github", @@ -10110,10 +10811,11 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT", + "peer": true }, "node_modules/react-markdown": { "version": "10.1.0", @@ -10142,15 +10844,6 @@ "react": ">=18" } }, - "node_modules/react-markdown/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/react-redux": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", @@ -10334,6 +11027,61 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/refractor/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/refractor/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/refractor/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/refractor/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/refractor/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -10374,15 +11122,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-katex/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/rehype-parse": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", @@ -10398,15 +11137,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-parse/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/rehype-prism-plus": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.1.tgz", @@ -10436,15 +11166,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-raw/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/rehype-slug": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", @@ -10462,15 +11183,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-slug/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/remark-breaks": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz", @@ -10553,15 +11265,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/remark-slug": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/remark-slug/-/remark-slug-8.0.0.tgz", @@ -10597,6 +11300,26 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/reselect": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", @@ -10625,13 +11348,13 @@ } }, "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/resolve-pkg-maps": { @@ -10672,6 +11395,13 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11012,6 +11742,13 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -11019,6 +11756,23 @@ "dev": true, "license": "MIT" }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/sonner": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.6.tgz", @@ -11048,6 +11802,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -11082,6 +11846,16 @@ "node": ">= 0.4" } }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, "node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -11100,19 +11874,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/string-width/node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -11120,22 +11881,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -11263,6 +12008,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -11406,12 +12167,39 @@ "node": ">=18" } }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -11663,6 +12451,19 @@ "dev": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -11682,12 +12483,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unified/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-filter": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-5.0.1.tgz", @@ -11699,12 +12494,6 @@ "unist-util-visit-parents": "^6.0.0" } }, - "node_modules/unist-util-filter/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-find-after": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", @@ -11719,12 +12508,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-find-after/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -11738,12 +12521,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-is/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", @@ -11757,12 +12534,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-remove-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", @@ -11777,12 +12548,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-remove-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -11796,12 +12561,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-stringify-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unist-util-visit": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", @@ -11831,18 +12590,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit-parents/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/unist-util-visit/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/unrs-resolver": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.0.tgz", @@ -12018,12 +12765,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-location/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/vfile-message": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", @@ -12038,18 +12779,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-message/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, - "node_modules/vfile/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "license": "MIT" - }, "node_modules/victory-vendor": { "version": "37.3.6", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", @@ -12221,6 +12950,34 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -12231,23 +12988,120 @@ "node": ">=18" } }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/zod": { - "version": "3.25.74", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.74.tgz", - "integrity": "sha512-J8poo92VuhKjNknViHRAIuuN6li/EwFbAC8OedzI8uxpEPGiXHGQu9wemIAioIpqgfB4SySaJhdk0mH5Y4ICBg==", + "version": "3.25.75", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.75.tgz", + "integrity": "sha512-OhpzAmVzabPOL6C3A3gpAifqr9MqihV/Msx3gor2b2kviCgcb+HM9SEOpMWwwNp9MRunWnhtAKUoo0AHhjyPPg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index a3d04ed..1e52b72 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,11 @@ "type-check": "tsc --noEmit", "type-check:watch": "tsc --noEmit --watch", "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json}\" --cache", - "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json}\" --cache", + "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json}\" --no-cache", "validate": "npm run type-check && npm run lint && npm run format:check", - "cli": "node ./scripts/cli.mjs" + "cli": "node ./scripts/cli.mjs", + "prepare": "husky", + "pre-commit": "lint-staged" }, "dependencies": { "@hookform/resolvers": "^5.1.1", @@ -89,8 +91,11 @@ "zod": "^3.25.74" }, "devDependencies": { + "@commitlint/cli": "^19.8.1", + "@commitlint/config-conventional": "^19.8.1", + "@eslint/js": "^9.30.1", + "@next/eslint-plugin-next": "^15.3.5", "@tailwindcss/postcss": "^4.1.11", - "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@types/cors": "^2.8.19", "@types/eslint": "^9.6.1", "@types/mime-types": "^3.0.1", @@ -108,6 +113,13 @@ "eslint": "^9.30.1", "eslint-config-next": "^15.3.5", "eslint-config-prettier": "^10.1.5", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-next": "^0.0.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "husky": "^9.1.7", + "lint-staged": "^16.1.2", "ora": "^8.2.0", "postcss": "^8.5.6", "prettier": "3.6.2", @@ -115,5 +127,10 @@ "tailwindcss": "^4.1.11", "tw-animate-css": "^1.3.5", "typescript": "^5.8.3" + }, + "overrides": { + "nextjs-toploader": { + "next": "$next" + } } } diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..c3d6adb --- /dev/null +++ b/renovate.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":dependencyDashboard", + ":semanticCommitTypeAll(chore)" + ], + "schedule": ["before 3am on Monday"], + "timezone": "UTC", + "packageRules": [ + { + "matchUpdateTypes": ["minor", "patch"], + "matchCurrentVersion": "!/^0/", + "automerge": true + }, + { + "matchDepTypes": ["devDependencies"], + "matchUpdateTypes": ["minor", "patch"], + "automerge": true + }, + { + "matchPackageNames": ["@types/node"], + "allowedVersions": "^20" + }, + { + "groupName": "ESLint and Prettier", + "matchPackageNames": [ + "eslint", + "prettier", + "@typescript-eslint/eslint-plugin", + "@typescript-eslint/parser", + "eslint-config-next", + "eslint-config-prettier", + "eslint-plugin-import", + "eslint-plugin-jsx-a11y", + "eslint-plugin-react", + "eslint-plugin-react-hooks" + ] + }, + { + "groupName": "React and Next.js", + "matchPackageNames": [ + "react", + "react-dom", + "@types/react", + "@types/react-dom", + "next" + ] + }, + { + "groupName": "Radix UI", + "matchPackagePatterns": ["^@radix-ui/"] + } + ], + "prConcurrentLimit": 3, + "prCreation": "immediate", + "labels": ["dependencies"], + "commitMessagePrefix": "chore(deps):", + "rangeStrategy": "bump" +} diff --git a/src/actions/configuration.ts b/src/actions/configuration.ts index 3e86b49..e2e9242 100644 --- a/src/actions/configuration.ts +++ b/src/actions/configuration.ts @@ -1,29 +1,10 @@ "use server"; -import { type AsyncZippable, strToU8, zipSync } from "fflate"; -import { type z } from "zod"; import { type ActionResponseSchema } from "@/types"; - -import { - configurationTemplate, - environmentTemplate, - parseEnvironment, - parseVersion1Config, - parseVersion2Config, -} from "@/lib/configurationHelper"; -import { - base64Decode, - base64Encode, - encryptionService, -} from "@/lib/utils.server"; - -import { - type Schema_App_Configuration, - type Schema_App_Configuration_Env, -} from "@/types/schema"; +import { base64Encode, base64Decode } from "@/lib/utils.server"; export async function GenerateServiceAccountB64( - serviceAccount: string, + serviceAccount: string ): Promise> { const b64 = base64Encode(serviceAccount, "standard"); @@ -52,240 +33,3 @@ export async function GenerateServiceAccountB64( data: b64, }; } - -export async function ProcessEnvironmentConfig( - configuration: string, -): Promise>> { - const data = parseEnvironment(configuration); - if ("message" in data && "details" in data) { - return { - success: false, - message: data.message, - error: data.details.join("\n"), - }; - } - // Verify service account - const serviceAccount = data.GD_SERVICE_B64; - const decoded = base64Decode(serviceAccount, "standard"); - if (decoded === null) { - data.GD_SERVICE_B64 = ""; - return { - success: true, - data, - message: "Environment loaded, but service account is invalid", - }; - } - - return { - success: true, - message: "Environment loaded", - data, - }; -} - -export async function ProcessConfiguration( - configuration: string, - version: "v1" | "v2" | "latest", -): Promise< - ActionResponseSchema< - Omit, "environment"> - > -> { - const data = - version === "v1" - ? parseVersion1Config(configuration) - : parseVersion2Config(configuration); - if ("message" in data && "details" in data) { - return { - success: false, - message: data.message, - error: data.details.join("\n"), - }; - } - - return { - success: true, - message: "Configuration loaded, but folder ID are not processed", - data, - }; -} - -export async function GenerateConfiguration( - values: z.infer, -): Promise< - ActionResponseSchema<{ configuration: string; env: string; zip: Blob }> -> { - const configurationMap: { key: string; value: string }[] = [ - { - key: "version", - value: values.version, - }, - { - key: "showGuideButton", - value: values.site.guideButton.toString(), - }, - { - key: "cacheControl", - value: `${values.api.cache.public ? "public, " : ""}max-age=${values.api.cache.maxAge}, s-maxage=${ - values.api.cache.sMaxAge - }${values.api.cache.staleWhileRevalidate ? ", stale-while-revalidate" : ""}`, - }, - { - key: "api.rootFolder", - value: await encryptionService.encrypt( - values.api.rootFolder, - values.environment.ENCRYPTION_KEY, - ), - }, - { - key: "api.isTeamDrive", - value: values.api.isTeamDrive.toString(), - }, - { - key: "api.sharedDrive", - value: values.api.sharedDrive - ? await encryptionService.encrypt( - values.api.sharedDrive, - values.environment.ENCRYPTION_KEY, - ) - : "", - }, - { - key: "api.itemsPerPage", - value: values.api.itemsPerPage.toString(), - }, - { - key: "api.searchResult", - value: values.api.searchResult.toString(), - }, - - { - key: "api.specialFile.readme", - value: values.api.specialFile.readme, - }, - { - key: "api.specialFile.banner", - value: values.api.specialFile.banner, - }, - { - key: "api.hiddenFiles", - value: `[${values.api.hiddenFiles.map((file) => `"${file}"`).join(", ")}]`, - }, - { - key: "api.proxyThumbnail", - value: values.api.proxyThumbnail.toString(), - }, - { - key: "api.streamMaxSize", - value: values.api.streamMaxSize.toString(), - }, - { - key: "api.maxFileSize", - value: values.api.maxFileSize.toString(), - }, - - { - key: "site.siteName", - value: values.site.siteName, - }, - { - key: "site.siteNameTemplate", - value: values.site.siteNameTemplate, - }, - { - key: "site.siteDescription", - value: values.site.siteDescription, - }, - { - key: "site.siteAuthor", - value: values.site.siteAuthor, - }, - { - key: "site.robots", - value: values.site.robots, - }, - { - key: "site.twitterHandle", - value: values.site.twitterHandle, - }, - { - key: "site.showFileExtension", - value: values.site.showFileExtension.toString(), - }, - - { - key: "site.breadcrumbMax", - value: values.site.breadcrumbMax.toString(), - }, - { - key: "site.toaster.position", - value: values.site.toaster.position, - }, - { - key: "site.toaster.duration", - value: values.site.toaster.duration.toString(), - }, - { - key: "site.navbarItems", - value: JSON.stringify(values.site.navbarItems, null, 2), - }, - { - key: "site.supports", - value: JSON.stringify(values.site.supports, null, 2), - }, - { - key: "site.footer", - value: JSON.stringify(values.site.footer, null, 2), - }, - ]; - let configuration = configurationTemplate; - for (const { key, value } of configurationMap) { - configuration = configuration.replace(`{{ ${key} }}`, value); - } - - const envMap: { key: string; value: string }[] = [ - { - key: "serviceAccount", - value: values.environment.GD_SERVICE_B64, - }, - { - key: "key", - value: values.environment.ENCRYPTION_KEY, - }, - - { - key: "domain", - value: values.environment.NEXT_PUBLIC_DOMAIN ?? "", - }, - ]; - let env = environmentTemplate; - for (const { key, value } of envMap) { - env = env.replace(`{{ ${key} }}`, value); - } - - const struct: AsyncZippable = { - ".env": [ - strToU8(env), - { - level: 9, - }, - ], - "gIndex.config.ts": [ - strToU8(configuration), - { - level: 9, - }, - ], - }; - const zip = zipSync(struct); - - return { - success: true, - message: "Configuration generated", - data: { - configuration, - env, - zip: new Blob([zip], { type: "application/zip" }), - }, - }; -} diff --git a/src/actions/files.ts b/src/actions/files.ts index fa4d2ec..ba4ae39 100644 --- a/src/actions/files.ts +++ b/src/actions/files.ts @@ -1,16 +1,22 @@ "use server"; -import { type z } from "zod"; +import config from "@/config/gIndex.config"; import { type ActionResponseSchema } from "@/types"; - -import { encryptionService, gdrive } from "@/lib/utils.server"; +import { type z } from "zod"; import { Schema_File, Schema_File_Shortcut } from "@/types/schema"; -import config from "@/config/gIndex.config"; +import { encryptionService, gdrive } from "@/lib/utils.server"; import { ValidatePaths } from "./paths"; +interface DriveFile { + mimeType?: string; + size?: string | number; + fileExtension?: string; + name?: string; +} + /** * List files in a folder * @param {object} options @@ -30,7 +36,7 @@ export async function ListFiles({ config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive ); const decryptedId = await encryptionService.decrypt( - id ?? config.apiConfig.rootFolder, + id ?? config.apiConfig.rootFolder ); const decryptedSharedDrive = isSharedDrive ? await encryptionService.decrypt(config.apiConfig.sharedDrive!) @@ -50,7 +56,7 @@ export async function ListFiles({ fields: `files(${config.apiConfig.defaultField}), nextPageToken`, orderBy: config.apiConfig.defaultOrder, pageSize: config.apiConfig.itemsPerPage, - pageToken: pageToken, + pageToken, ...(decryptedSharedDrive && { supportsAllDrives: true, includeItemsFromAllDrives: true, @@ -122,10 +128,10 @@ export async function ListFiles({ * @param id - File ID to fetch */ export async function GetFile( - id: string, + id: string ): Promise | null>> { const decryptedId = await encryptionService.decrypt( - id ?? config.apiConfig.rootFolder, + id ?? config.apiConfig.rootFolder ); const { data } = await gdrive.files.get({ @@ -197,7 +203,7 @@ export async function GetReadme(id: string | null = null): Promise< config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive ); const decryptedId = await encryptionService.decrypt( - id ?? config.apiConfig.rootFolder, + id ?? config.apiConfig.rootFolder ); const decryptedSharedDrive = isSharedDrive ? await encryptionService.decrypt(config.apiConfig.sharedDrive!) @@ -237,7 +243,7 @@ export async function GetReadme(id: string | null = null): Promise< } else { file = data.files.find((file) => file.mimeType === "text/markdown"); file ??= data.files.find( - (file) => file.mimeType === "application/vnd.google-apps.shortcut", + (file) => file.mimeType === "application/vnd.google-apps.shortcut" ); } @@ -282,7 +288,7 @@ export async function GetReadme(id: string | null = null): Promise< }, { responseType: "text", - }, + } ); return { @@ -306,7 +312,7 @@ export async function GetReadme(id: string | null = null): Promise< }, { responseType: "text", - }, + } ); return { success: true, @@ -330,13 +336,13 @@ export async function GetReadme(id: string | null = null): Promise< * @param id - Folder ID to fetch, default is root folder */ export async function GetBanner( - id: string | null = null, + id: string | null = null ): Promise> { const isSharedDrive = !!( config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive ); const decryptedId = await encryptionService.decrypt( - id ?? config.apiConfig.rootFolder, + id ?? config.apiConfig.rootFolder ); const decryptedSharedDrive = isSharedDrive ? await encryptionService.decrypt(config.apiConfig.sharedDrive!) @@ -381,7 +387,7 @@ export async function GetBanner( * @param id - File ID to fetch */ export async function GetContent( - id: string, + id: string ): Promise> { const decryptedId = await encryptionService.decrypt(id); @@ -393,7 +399,7 @@ export async function GetContent( }, { responseType: "text", - }, + } ); if (status !== 200) return { @@ -414,7 +420,7 @@ export async function GetContent( * @param paths - Paths to check */ export async function GetSiblingsMedia( - paths: string[], + paths: string[] ): Promise[]>> { const pathIds = await ValidatePaths(paths); if (!pathIds.success) @@ -424,7 +430,7 @@ export async function GetSiblingsMedia( error: pathIds.error, }; const folderPaths = pathIds.data.filter( - (item) => item.mimeType === "application/vnd.google-apps.folder", + (item) => item.mimeType === "application/vnd.google-apps.folder" ); const parentId = @@ -531,10 +537,16 @@ export async function GetStorageInfo(): Promise< const isSharedDrive = !!( config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive ); - - console.log("[GetStorageInfo] isSharedDrive:", isSharedDrive); - console.log("[GetStorageInfo] config.apiConfig.isTeamDrive:", config.apiConfig.isTeamDrive); - console.log("[GetStorageInfo] config.apiConfig.sharedDrive:", config.apiConfig.sharedDrive); + + console.info("[GetStorageInfo] isSharedDrive:", isSharedDrive); + console.info( + "[GetStorageInfo] config.apiConfig.isTeamDrive:", + config.apiConfig.isTeamDrive + ); + console.info( + "[GetStorageInfo] config.apiConfig.sharedDrive:", + config.apiConfig.sharedDrive + ); if (isSharedDrive) { // For shared drives, get drive info and calculate usage from files @@ -548,93 +560,114 @@ export async function GetStorageInfo(): Promise< fields: "id, name, capabilities", }); - // Calculate comprehensive storage and file statistics - let totalSize = 0; - let totalFiles = 0; - let totalFolders = 0; - const fileTypeStats: { [key: string]: { count: number; size: number } } = {}; - let pageToken: string | null | undefined = null; - - console.log("[GetStorageInfo] Starting comprehensive scan of shared drive..."); - - do { - const response: any = await gdrive.files.list({ - q: "trashed = false", - fields: "files(id,name,size,mimeType,fileExtension), nextPageToken", - supportsAllDrives: true, - includeItemsFromAllDrives: true, - driveId: decryptedSharedDrive, - corpora: "drive", - pageSize: 1000, - pageToken: pageToken || undefined, - }); - - if (response.data.files) { - for (const file of response.data.files) { - if (file.mimeType === "application/vnd.google-apps.folder") { - totalFolders++; - } else { - totalFiles++; - if (file.size) { - const fileSize = Number(file.size); - totalSize += fileSize; - - // Categorize by file type - const extension = file.fileExtension || 'no-extension'; - const mimeType = file.mimeType || 'unknown'; - - let category = 'other'; - if (mimeType.startsWith('image/')) category = 'images'; - else if (mimeType.startsWith('video/')) category = 'videos'; - else if (mimeType.startsWith('audio/')) category = 'audio'; - else if (mimeType.includes('pdf')) category = 'documents'; - else if (mimeType.includes('text') || mimeType.includes('document')) category = 'documents'; - else if (extension === 'iso') category = 'iso'; - else if (extension === 'zip' || extension === 'rar' || extension === '7z') category = 'archives'; - - if (!fileTypeStats[category]) { - fileTypeStats[category] = { count: 0, size: 0 }; - } - fileTypeStats[category].count++; - fileTypeStats[category].size += fileSize; - } - } - } - } - - pageToken = response.data.nextPageToken; - console.log(`[GetStorageInfo] Processed page, total files so far: ${totalFiles}, folders: ${totalFolders}, size: ${(totalSize / (1024**4)).toFixed(2)} TB`); - } while (pageToken); - - console.log("[GetStorageInfo] Final stats:", { - totalFiles, - totalFolders, - totalSize, - totalSizeTB: (totalSize / (1024**4)).toFixed(2), - fileTypeStats - }); - - // Set the actual org limit: 100TB - const orgLimit = 100 * 1024 * 1024 * 1024 * 1024; // 100TB in bytes - - return { - success: true, - message: "Shared drive storage information retrieved", - data: { - storageUsed: totalSize, - storageLimit: orgLimit, - storageUsedInDrive: totalSize, - storageUsedInTrash: 0, // Shared drives don't have individual trash tracking - totalFiles, - totalFolders, - fileTypeStats, - driveInfo: { - name: driveData.name || "Unknown", - id: driveData.id || "", - capabilities: driveData.capabilities, - }, - }, - }; + // Calculate comprehensive storage and file statistics + let totalSize = 0; + let totalFiles = 0; + let totalFolders = 0; + const fileTypeStats: { [key: string]: { count: number; size: number } } = + {}; + let pageToken: string | null | undefined = null; + + console.info( + "[GetStorageInfo] Starting comprehensive scan of shared drive..." + ); + + do { + const response: unknown = await gdrive.files.list({ + q: "trashed = false", + fields: "files(id,name,size,mimeType,fileExtension), nextPageToken", + supportsAllDrives: true, + includeItemsFromAllDrives: true, + driveId: decryptedSharedDrive, + corpora: "drive", + pageSize: 1000, + pageToken: pageToken || undefined, + }); + + if ( + response && + (response as { data: { files: unknown[]; nextPageToken?: string } }) + .data.files + ) { + for (const file of (response as { data: { files: unknown[] } }).data + .files) { + const f = file as DriveFile; + if (f.mimeType === "application/vnd.google-apps.folder") { + totalFolders++; + } else { + totalFiles++; + if (f.size) { + const fileSize = Number(f.size); + totalSize += fileSize; + + // Categorize by file type + const extension = f.fileExtension || "no-extension"; + const mimeType = f.mimeType || "unknown"; + + let category = "other"; + if (mimeType.startsWith("image/")) category = "images"; + else if (mimeType.startsWith("video/")) category = "videos"; + else if (mimeType.startsWith("audio/")) category = "audio"; + else if (mimeType.includes("pdf")) category = "documents"; + else if ( + mimeType.includes("text") || + mimeType.includes("document") + ) + category = "documents"; + else if (extension === "iso") category = "iso"; + else if ( + extension === "zip" || + extension === "rar" || + extension === "7z" + ) + category = "archives"; + + if (!fileTypeStats[category]) { + fileTypeStats[category] = { count: 0, size: 0 }; + } + fileTypeStats[category].count++; + fileTypeStats[category].size += fileSize; + } + } + } + } + + pageToken = (response as { data: { nextPageToken?: string } }).data + .nextPageToken; + console.info( + `[GetStorageInfo] Processed page, total files so far: ${totalFiles}, folders: ${totalFolders}, size: ${(totalSize / 1024 ** 4).toFixed(2)} TB` + ); + } while (pageToken); + + console.info("[GetStorageInfo] Final stats:", { + totalFiles, + totalFolders, + totalSize, + totalSizeTB: (totalSize / 1024 ** 4).toFixed(2), + fileTypeStats, + }); + + // Set the actual org limit: 100TB + const orgLimit = 100 * 1024 * 1024 * 1024 * 1024; // 100TB in bytes + + return { + success: true, + message: "Shared drive storage information retrieved", + data: { + storageUsed: totalSize, + storageLimit: orgLimit, + storageUsedInDrive: totalSize, + storageUsedInTrash: 0, // Shared drives don't have individual trash tracking + totalFiles, + totalFolders, + fileTypeStats, + driveInfo: { + name: driveData.name || "Unknown", + id: driveData.id || "", + capabilities: driveData.capabilities, + }, + }, + }; } else { // Personal drive storage (original logic) const { data } = await gdrive.about.get({ diff --git a/src/actions/paths.ts b/src/actions/paths.ts index 1083181..534cc7a 100644 --- a/src/actions/paths.ts +++ b/src/actions/paths.ts @@ -1,11 +1,10 @@ "use server"; +import config from "@/config/gIndex.config"; import { type ActionResponseSchema } from "@/types"; import { encryptionService, gdrive } from "@/lib/utils.server"; -import config from "@/config/gIndex.config"; - /** * Get file paths from the root folder to the file. * @param {string} fileName - The file name. @@ -14,10 +13,10 @@ import config from "@/config/gIndex.config"; */ export async function GetFilePaths( fileName: string, - parentId?: string, + parentId?: string ): Promise> { const decryptedRootId = await encryptionService.decrypt( - config.apiConfig.rootFolder, + config.apiConfig.rootFolder ); if (!decryptedRootId) return { @@ -64,7 +63,7 @@ type PathFetch = { * @returns {ActionResponseSchema<{ id: string; path: string; mimeType: string; }[]>} - The validated paths. */ export async function ValidatePaths( - paths: string[], + paths: string[] ): Promise< ActionResponseSchema<{ id: string; path: string; mimeType: string }[]> > { @@ -72,7 +71,7 @@ export async function ValidatePaths( config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive ); const decryptedRootId = await encryptionService.decrypt( - config.apiConfig.rootFolder, + config.apiConfig.rootFolder ); const decryptedSharedDrive = isSharedDrive ? await encryptionService.decrypt(config.apiConfig.sharedDrive!) diff --git a/src/actions/search.ts b/src/actions/search.ts index 0ffe749..edf751a 100644 --- a/src/actions/search.ts +++ b/src/actions/search.ts @@ -1,18 +1,17 @@ "use server"; -import { type z } from "zod"; +import config from "@/config/gIndex.config"; import { type ActionResponseSchema } from "@/types"; - -import { encryptionService, gdrive } from "@/lib/utils.server"; +import { type z } from "zod"; import { Schema_File } from "@/types/schema"; -import config from "@/config/gIndex.config"; +import { encryptionService, gdrive } from "@/lib/utils.server"; import { GetFilePaths } from "./paths"; export async function SearchFiles( - query: string, + query: string ): Promise[]>> { const isSharedDrive = !!( config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive @@ -96,13 +95,13 @@ export async function SearchFiles( } export async function GetSearchResultPath( - id: string, + id: string ): Promise> { const isSharedDrive = !!( config.apiConfig.isTeamDrive && config.apiConfig.sharedDrive ); const decryptedId = await encryptionService.decrypt( - id ?? config.apiConfig.rootFolder, + id ?? config.apiConfig.rootFolder ); const { data } = await gdrive.files.get({ diff --git a/src/actions/token.ts b/src/actions/token.ts index ff439a3..947831e 100644 --- a/src/actions/token.ts +++ b/src/actions/token.ts @@ -1,12 +1,12 @@ "use server"; -import { type z } from "zod"; import { type ActionResponseSchema } from "@/types"; - -import { encryptionService } from "@/lib/utils.server"; +import { type z } from "zod"; import { type Schema_File, Schema_FileToken } from "@/types/schema"; +import { encryptionService } from "@/lib/utils.server"; + /** * Create a token to download a file * @param file - File data @@ -14,7 +14,7 @@ import { type Schema_File, Schema_FileToken } from "@/types/schema"; */ export async function CreateFileToken( file: z.infer, - expiredIn: number = 3600 * 1000, // 1 hour default + expiredIn: number = 3600 * 1000 // 1 hour default ): Promise> { const tokenObject = { id: file.encryptedId, @@ -30,7 +30,7 @@ export async function CreateFileToken( }; const token = await encryptionService.encrypt( - JSON.stringify(parsedTokenObject.data), + JSON.stringify(parsedTokenObject.data) ); return { @@ -45,7 +45,7 @@ export async function CreateFileToken( * @param token - The token to validate */ export async function ValidateFileToken( - token: string, + token: string ): Promise>> { const decryptedToken = await encryptionService.decrypt(token); const parsedToken = Schema_FileToken.safeParse(JSON.parse(decryptedToken)); diff --git a/src/app/[...rest]/page.tsx b/src/app/[...rest]/page.tsx index 6d23d11..5af845f 100644 --- a/src/app/[...rest]/page.tsx +++ b/src/app/[...rest]/page.tsx @@ -2,6 +2,12 @@ import { type Metadata, type ResolvedMetadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; +import { GetBanner, GetFile, GetReadme, ListFiles } from "@/actions/files"; +import { ValidatePaths } from "@/actions/paths"; + +import { getFileType } from "@/lib/previewHelper"; +import { formatPathToBreadcrumb } from "@/lib/utils"; + import { FileActions, FileBreadcrumb, @@ -14,12 +20,6 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import Icon from "@/components/ui/icon"; -import { getFileType } from "@/lib/previewHelper"; -import { formatPathToBreadcrumb } from "@/lib/utils"; - -import { GetBanner, GetFile, GetReadme, ListFiles } from "@/actions/files"; -import { ValidatePaths } from "@/actions/paths"; - export const revalidate = 3600; export const dynamic = "force-static"; @@ -31,7 +31,7 @@ type Props = { export async function generateMetadata( { params }: Props, - parent: ResolvedMetadata, + parent: ResolvedMetadata ): Promise { const { rest } = await params; @@ -71,7 +71,7 @@ export default async function RestPage({ params }: Props) { if (!currentPath) return ; - const prevPath = "/" + rest.slice(0, -1).join("/"); + const prevPath = `/${rest.slice(0, -1).join("/")}`; const Layout: React.FC<{ children: React.ReactNode; diff --git a/src/app/api/download/[...rest]/route.ts b/src/app/api/download/[...rest]/route.ts index 1854bbc..2bb1284 100644 --- a/src/app/api/download/[...rest]/route.ts +++ b/src/app/api/download/[...rest]/route.ts @@ -1,19 +1,17 @@ import { type NextRequest, NextResponse } from "next/server"; -import { encryptionService, gdrive } from "@/lib/utils.server"; - import { GetFile } from "@/actions/files"; import { ValidatePaths } from "@/actions/paths"; - import config from "@/config/gIndex.config"; -export const runtime = "nodejs"; +import { encryptionService, gdrive } from "@/lib/utils.server"; +export const runtime = "nodejs"; export const dynamic = "force-static"; export async function GET( request: NextRequest, - { params }: { params: Promise<{ rest: string[] }> }, + { params }: { params: Promise<{ rest: string[] }> } ) { const { rest } = await params; const sp = new URL(request.nextUrl).searchParams; @@ -57,7 +55,7 @@ export async function GET( forceRedirect ) { const decryptedContentUrl = await encryptionService.decrypt( - file.data.encryptedWebContentLink, + file.data.encryptedWebContentLink ); const contentUrl = new URL(decryptedContentUrl); contentUrl.searchParams.set("confirm", "1"); @@ -78,7 +76,7 @@ export async function GET( }, { responseType: "stream", - }, + } ); const fileBuffer = await new Promise((res, rej) => { const chunks: Buffer[] = []; @@ -116,7 +114,7 @@ export async function GET( }, { status: Number(status), - }, + } ); } } diff --git a/src/app/api/internal/check/route.ts b/src/app/api/internal/check/route.ts index d9fadd1..8717e28 100644 --- a/src/app/api/internal/check/route.ts +++ b/src/app/api/internal/check/route.ts @@ -1,18 +1,17 @@ import { NextResponse } from "next/server"; -import { encryptionService } from "@/lib/utils.server"; - import config from "@/config/gIndex.config"; -export const runtime = "nodejs"; +import { encryptionService } from "@/lib/utils.server"; +export const runtime = "nodejs"; export const dynamic = "force-dynamic"; export async function GET() { try { if (process.env.NODE_ENV !== "development") { throw new Error( - "This route is only available in development environment", + "This route is only available in development environment" ); } @@ -26,7 +25,7 @@ export async function GET() { rootId, sharedDriveId, }, - { status: 200 }, + { status: 200 } ); } catch (error) { const e = error as Error; diff --git a/src/app/api/internal/encrypt/route.ts b/src/app/api/internal/encrypt/route.ts index e8e9948..55ba643 100644 --- a/src/app/api/internal/encrypt/route.ts +++ b/src/app/api/internal/encrypt/route.ts @@ -14,7 +14,7 @@ export async function GET(request: NextRequest) { if (!query) return new NextResponse( "Add query parameter 'q' with the value to encrypt", - { status: 400 }, + { status: 400 } ); if (process.env.NODE_ENV !== "development" && !key) { @@ -24,7 +24,7 @@ export async function GET(request: NextRequest) { const encrypted = await encryptionService.encrypt(query, key ?? undefined); const decrypted = await encryptionService.decrypt( encrypted, - key ?? undefined, + key ?? undefined ); return NextResponse.json( @@ -36,7 +36,7 @@ export async function GET(request: NextRequest) { decryptedValue: decrypted, key: key ?? process.env.ENCRYPTION_KEY, }, - { status: 200 }, + { status: 200 } ); } catch (error) { const e = error as Error; diff --git a/src/app/api/internal/storage/route.ts b/src/app/api/internal/storage/route.ts index a1372e4..4558e03 100644 --- a/src/app/api/internal/storage/route.ts +++ b/src/app/api/internal/storage/route.ts @@ -1,11 +1,13 @@ -export const runtime = "nodejs" import { NextResponse } from "next/server"; + import { GetStorageInfo } from "@/actions/files"; +export const runtime = "nodejs"; + export async function GET() { try { const result = await GetStorageInfo(); - + if (!result.success) { return NextResponse.json( { error: result.message || "Failed to get storage info" }, @@ -14,17 +16,17 @@ export async function GET() { } // Format the data for easier consumption - const { - storageUsed, - storageLimit, - storageUsedInDrive, - storageUsedInTrash, + const { + storageUsed, + storageLimit, + storageUsedInDrive, + storageUsedInTrash, totalFiles, totalFolders, fileTypeStats, - driveInfo + driveInfo, } = result.data; - + // Convert bytes to TB for display const formatBytes = (bytes: number) => ({ bytes, @@ -37,15 +39,23 @@ export async function GET() { limit: formatBytes(storageLimit), drive: formatBytes(storageUsedInDrive), trash: formatBytes(storageUsedInTrash), - percentage: storageLimit > 0 ? Number(((storageUsed / storageLimit) * 100).toFixed(1)) : 0, + percentage: + storageLimit > 0 + ? Number(((storageUsed / storageLimit) * 100).toFixed(1)) + : 0, totalFiles, totalFolders, - fileTypeStats: Object.entries(fileTypeStats).map(([type, stats]) => ({ - type, - count: stats.count, - size: formatBytes(stats.size), - percentage: storageUsed > 0 ? Number(((stats.size / storageUsed) * 100).toFixed(1)) : 0 - })).sort((a, b) => b.size.bytes - a.size.bytes), + fileTypeStats: Object.entries(fileTypeStats) + .map(([type, stats]) => ({ + type, + count: stats.count, + size: formatBytes(stats.size), + percentage: + storageUsed > 0 + ? Number(((stats.size / storageUsed) * 100).toFixed(1)) + : 0, + })) + .sort((a, b) => b.size.bytes - a.size.bytes), driveInfo: driveInfo || null, isSharedDrive: !!driveInfo, }); @@ -56,4 +66,4 @@ export async function GET() { { status: 500 } ); } -} \ No newline at end of file +} diff --git a/src/app/api/og/[encryptedId]/route.ts b/src/app/api/og/[encryptedId]/route.ts index 5666787..2499f02 100644 --- a/src/app/api/og/[encryptedId]/route.ts +++ b/src/app/api/og/[encryptedId]/route.ts @@ -1,11 +1,10 @@ import { type NextRequest, NextResponse } from "next/server"; -import { encryptionService, gdrive } from "@/lib/utils.server"; - import config from "@/config/gIndex.config"; -export const runtime = "nodejs"; +import { encryptionService, gdrive } from "@/lib/utils.server"; +export const runtime = "nodejs"; export const dynamic = "force-static"; type Props = { @@ -48,7 +47,7 @@ export async function GET(request: NextRequest, { params }: Props) { }, { status: 500, - }, + } ); } } diff --git a/src/app/api/raw/[...rest]/route.ts b/src/app/api/raw/[...rest]/route.ts index 20b63d5..5aebf2d 100644 --- a/src/app/api/raw/[...rest]/route.ts +++ b/src/app/api/raw/[...rest]/route.ts @@ -1,17 +1,16 @@ import { type NextRequest, NextResponse } from "next/server"; -import { encryptionService } from "@/lib/utils.server"; - import { GetFile } from "@/actions/files"; import { ValidatePaths } from "@/actions/paths"; -export const runtime = "nodejs"; +import { encryptionService } from "@/lib/utils.server"; +export const runtime = "nodejs"; export const dynamic = "force-static"; export async function GET( request: NextRequest, - { params }: { params: Promise<{ rest: string[] }> }, + { params }: { params: Promise<{ rest: string[] }> } ) { const { rest } = await params; const paths = rest.map((path) => { @@ -47,7 +46,7 @@ export async function GET( } const decryptedLink = await encryptionService.decrypt( - fileMeta.data.encryptedWebContentLink, + fileMeta.data.encryptedWebContentLink ); return new NextResponse(null, { status: 302, @@ -73,7 +72,7 @@ export async function GET( headers: { "Cache-Control": "no-store", // avoid caching error responses }, - }, + } ); } } diff --git a/src/app/api/thumb/[encryptedId]/route.ts b/src/app/api/thumb/[encryptedId]/route.ts index 381b3ae..548f971 100644 --- a/src/app/api/thumb/[encryptedId]/route.ts +++ b/src/app/api/thumb/[encryptedId]/route.ts @@ -1,11 +1,11 @@ import { type NextRequest, NextResponse } from "next/server"; -import { z } from "zod"; + +import config from "@/config/gIndex.config"; import { IS_DEV } from "@/constant"; +import { z } from "zod"; import { encryptionService } from "@/lib/utils.server"; -import config from "@/config/gIndex.config"; - export const runtime = "nodejs"; export const dynamic = "force-dynamic"; @@ -61,7 +61,7 @@ export async function GET(request: NextRequest, { params }: Props) { }, { status: 500, - }, + } ); } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index fea2075..c796e0f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,16 +1,16 @@ import { type Metadata } from "next"; import { JetBrains_Mono, Outfit, Source_Sans_3 } from "next/font/google"; import { headers } from "next/headers"; -import { BASE_URL } from "@/constant"; - -import { Footer, Navbar, Provider, ToTop } from "@/components/layout"; -import { cn, formatFooterContent } from "@/lib/utils"; +import config from "@/config/gIndex.config"; +import { BASE_URL } from "@/constant"; import "@/styles/code-highlight.css"; import "@/styles/globals.css"; import "@/styles/markdown.css"; -import config from "@/config/gIndex.config"; +import { cn, formatFooterContent } from "@/lib/utils"; + +import { Footer, Navbar, Provider, ToTop } from "@/components/layout"; const sourceSans3 = Source_Sans_3({ weight: ["300", "400", "600", "700"], @@ -36,14 +36,14 @@ const jetbrainsMono = JetBrains_Mono({ export const metadata: Metadata = { metadataBase: new URL( - BASE_URL.includes("http") ? BASE_URL : `https://${BASE_URL}`, + BASE_URL.includes("http") ? BASE_URL : `https://${BASE_URL}` ), title: { default: config.siteConfig.siteName, template: config.siteConfig.siteNameTemplate?.replace( "%t", - config.siteConfig.siteName, + config.siteConfig.siteName ) ?? "%s", }, description: config.siteConfig.siteDescription, @@ -93,7 +93,7 @@ export default async function RootLayout({ : "h-full min-h-screen bg-background", jetbrainsMono.variable, sourceSans3.variable, - outfit.variable, + outfit.variable )} > @@ -118,7 +117,7 @@ export default async function RootLayout({ "mx-auto h-auto w-full max-w-(--breakpoint-desktop)", "relative left-0 top-0", "flex grow flex-col gap-4 px-2 py-6 mobile:px-3 tablet:px-4", - "tablet:gap-6", + "tablet:gap-6" )} > {children} diff --git a/src/app/ngdi-internal/configurator/page.tsx b/src/app/ngdi-internal/configurator/page.tsx deleted file mode 100644 index c0f89d2..0000000 --- a/src/app/ngdi-internal/configurator/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { type Metadata } from "next"; - -import { ConfiguratorPage } from "@/components/internal"; - -export const dynamic = "force-static"; - -export const metadata: Metadata = { - title: "Configurator", - description: "Generate configuration file for your index", -}; - -export default function InternalConfiguratorPage() { - return ; -} diff --git a/src/app/page.tsx b/src/app/page.tsx index 6abf6db..c03d9aa 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,6 +1,12 @@ "use client"; -import { Suspense, useState, useEffect } from "react"; +import { Suspense, useEffect, useState } from "react"; + +import { GetReadme, ListFiles } from "@/actions/files"; +import config from "@/config/gIndex.config"; + +import { cn } from "@/lib/utils"; + import { FileActions, FileBreadcrumb, @@ -8,17 +14,13 @@ import { FileReadme, } from "@/components/explorer"; import { Error as ErrorComponent } from "@/components/layout"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import Icon from "@/components/ui/icon"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; -import Icon from "@/components/ui/icon"; - -import { cn } from "@/lib/utils"; - -import { GetReadme, ListFiles } from "@/actions/files"; - -import config from "@/config/gIndex.config"; +import { type Schema_File } from "@/types/schema"; +import { type z } from "zod"; type StorageInfo = { usage: { bytes: number; tb: number; gb: number }; @@ -40,7 +42,19 @@ type StorageInfo = { isSharedDrive: boolean; }; - +// Define the expected type for data objects +interface FileData { + data: { + files: unknown[]; + nextPageToken?: string; + }; +} +interface ReadmeData { + data: { + content: string; + type: string; + }; +} // Fallback components for Suspense const FileActionsFallback = () => ( @@ -72,13 +86,13 @@ const SystemInfoPanel = ({ rootItemCount }: { rootItemCount: number }) => { useEffect(() => { const fetchStorageInfo = async () => { try { - const response = await fetch('/api/internal/storage'); + const response = await fetch("/api/internal/storage"); if (response.ok) { const data = await response.json(); setStorageInfo(data); } } catch (error) { - console.error('Failed to fetch storage info:', error); + console.error("Failed to fetch storage info:", error); } finally { setIsLoading(false); } @@ -92,7 +106,11 @@ const SystemInfoPanel = ({ rootItemCount }: { rootItemCount: number }) => {
- +
System Information
@@ -136,9 +154,9 @@ const SystemInfoPanel = ({ rootItemCount }: { rootItemCount: number }) => { - + - + {/* Storage Information */}
@@ -159,9 +177,11 @@ const SystemInfoPanel = ({ rootItemCount }: { rootItemCount: number }) => { )}
-
{storageInfo && ( @@ -170,7 +190,7 @@ const SystemInfoPanel = ({ rootItemCount }: { rootItemCount: number }) => {
)}
- + {/* File Type Statistics */} {storageInfo && storageInfo.fileTypeStats.length > 0 && ( <> @@ -187,14 +207,19 @@ const SystemInfoPanel = ({ rootItemCount }: { rootItemCount: number }) => { "#10b981", // emerald-500 "#f59e0b", // amber-500 "#06b6d4", // cyan-500 - "#ec4899" // pink-500 + "#ec4899", // pink-500 ]; return ( -
+
-
{stat.type}
@@ -224,7 +249,7 @@ export default function RootPage() { try { const [filesResult, readmeResult] = await Promise.all([ ListFiles(), - GetReadme() + GetReadme(), ]); if (!filesResult.success) { @@ -240,7 +265,7 @@ export default function RootPage() { setData(filesResult); setReadme(readmeResult); } catch (err) { - setError(err instanceof Error ? err : new Error('Failed to load data')); + setError(err instanceof Error ? err : new Error("Failed to load data")); } finally { setIsLoading(false); } @@ -251,7 +276,10 @@ export default function RootPage() { if (error) return ; if (isLoading) return
Loading...
; - if (!data || !readme) return
No data available
; + if (!data || !readme) + return
No data available
; + + const files = (data as FileData).data?.files as z.infer[]; return (
@@ -266,7 +294,9 @@ export default function RootPage() {
- Shared Drive • Connected + + Shared Drive • Connected +
Last sync: {new Date().toLocaleTimeString()}
@@ -276,7 +306,9 @@ export default function RootPage() {
{/* System Info Sidebar */}
- +
{/* Main Content */} @@ -287,7 +319,7 @@ export default function RootPage() {
File System - {(data as any)?.data?.files?.length || 0} items + {(data as FileData).data?.files?.length || 0} items
@@ -301,19 +333,21 @@ export default function RootPage() {
- {(readme as any)?.data && ( + {(readme as ReadmeData).data && ( }> )} diff --git a/src/components/explorer/FileActions.tsx b/src/components/explorer/FileActions.tsx index e4519d5..040acae 100644 --- a/src/components/explorer/FileActions.tsx +++ b/src/components/explorer/FileActions.tsx @@ -2,6 +2,12 @@ import React, { useCallback, useState } from "react"; +import { useLayout } from "@/context/layoutContext"; + +import { cn } from "@/lib/utils"; + +import useLoading from "@/hooks/useLoading"; + import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -17,10 +23,6 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; -import { useLayout } from "@/context/layoutContext"; -import useLoading from "@/hooks/useLoading"; -import { cn } from "@/lib/utils"; - const FileActions = React.memo(() => { const loading = useLoading(); const { layout, setLayout, isPending } = useLayout(); @@ -32,7 +34,7 @@ const FileActions = React.memo(() => { setLayout(newLayout); setLayoutOpen(false); }, - [setLayout], + [setLayout] ); if (loading) { diff --git a/src/components/explorer/FileBreadcrumbs.tsx b/src/components/explorer/FileBreadcrumbs.tsx index ee00949..c26859e 100644 --- a/src/components/explorer/FileBreadcrumbs.tsx +++ b/src/components/explorer/FileBreadcrumbs.tsx @@ -1,9 +1,18 @@ "use client"; -import Link from "next/link"; import { Fragment, useState } from "react"; -import { type z } from "zod"; + +import Link from "next/link"; + +import config from "@/config/gIndex.config"; import { Home } from "lucide-react"; +import { type z } from "zod"; + +import { type Schema_Breadcrumb } from "@/types/schema"; + +import { cn } from "@/lib/utils"; + +import useLoading from "@/hooks/useLoading"; import { Breadcrumb, @@ -21,13 +30,6 @@ import { ResponsiveDropdownMenuTrigger, } from "@/components/ui/dropdown-menu.responsive"; import { Skeleton } from "@/components/ui/skeleton"; -import { cn } from "@/lib/utils"; - -import useLoading from "@/hooks/useLoading"; - -import { type Schema_Breadcrumb } from "@/types/schema"; - -import config from "@/config/gIndex.config"; type Props = { data?: z.infer[]; @@ -48,115 +50,118 @@ export default function FileBreadcrumb({ data }: Props) { .slice(0, index + 1) .map((item) => item.href) .filter(Boolean); - + return pathSegments.length > 0 ? `/${pathSegments.join("/")}` : "/"; }; // Split breadcrumbs for ellipsis handling const maxVisible = config.siteConfig.breadcrumbMax; const shouldShowEllipsis = breadcrumbs.length > maxVisible; - const hiddenItems = shouldShowEllipsis + const hiddenItems = shouldShowEllipsis ? breadcrumbs.slice(0, -maxVisible + 1) : []; - const visibleItems = shouldShowEllipsis + const visibleItems = shouldShowEllipsis ? breadcrumbs.slice(-maxVisible + 1) : breadcrumbs; return ( - - {/* Root */} - - - - - Home - - - - - {breadcrumbs.length > 0 && ( - <> - - - {/* Ellipsis dropdown for hidden items */} - {shouldShowEllipsis && ( - <> - - - - - - - {hiddenItems.map((item, index) => ( - - - {item.label} - - - ))} - - - - - - )} - - {/* Visible breadcrumb items */} - {visibleItems.map((item, index) => { - const actualIndex = shouldShowEllipsis - ? hiddenItems.length + index - : index; - const isLast = actualIndex === breadcrumbs.length - 1; - const href = item.href ? buildHref(actualIndex) : undefined; - - return ( - - - {href && !isLast ? ( - + + {/* Root */} + + + + + Home + + + + + {breadcrumbs.length > 0 && ( + <> + + + {/* Ellipsis dropdown for hidden items */} + {shouldShowEllipsis && ( + <> + + + + + + + {hiddenItems.map((item, index) => ( + - {item.label} + {item.label} - - ) : ( - + ))} + + + + + + )} + + {/* Visible breadcrumb items */} + {visibleItems.map((item, index) => { + const actualIndex = shouldShowEllipsis + ? hiddenItems.length + index + : index; + const isLast = actualIndex === breadcrumbs.length - 1; + const href = item.href ? buildHref(actualIndex) : undefined; + + return ( + + + {href && !isLast ? ( + + {item.label} - - )} - - {!isLast && } - - ); - })} - - )} - - + + + ) : ( + + {item.label} + + )} + + {!isLast && } + + ); + })} + + )} + + ); } diff --git a/src/components/explorer/FileItem.tsx b/src/components/explorer/FileItem.tsx index f472705..0252323 100644 --- a/src/components/explorer/FileItem.tsx +++ b/src/components/explorer/FileItem.tsx @@ -1,10 +1,20 @@ "use client"; -import { usePathname } from "next/navigation"; import React, { useCallback, useMemo, useState } from "react"; + +import { usePathname } from "next/navigation"; + +import config from "@/config/gIndex.config"; +import { type TLayout } from "@/context/layoutContext"; import { toast } from "sonner"; import { type z } from "zod"; +import { type Schema_File } from "@/types/schema"; + +import { bytesToReadable, durationToReadable, formatDate } from "@/lib/utils"; + +import useRouter from "@/hooks/usePRouter"; + import { Button } from "@/components/ui/button"; import { Card, CardHeader, CardTitle } from "@/components/ui/card"; import { @@ -28,18 +38,8 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import Icon, { type IconName } from "@/components/ui/icon"; +import Image from "next/image"; -import { type TLayout } from "@/context/layoutContext"; -import useRouter from "@/hooks/usePRouter"; -import { - bytesToReadable, - durationToReadable, - formatDate, -} from "@/lib/utils"; - -import { type Schema_File } from "@/types/schema"; - -import config from "@/config/gIndex.config"; // import { GetMostRecentFileUpdate } from "@/actions/folder"; type Props = { @@ -95,7 +95,7 @@ const FileInfoModal = ({ const downloadUrl = useMemo(() => { const url = new URL( `/api/download${pathname}/${file.name}`.replace(/\/+/g, "/"), - config.basePath, + config.basePath ); return url.toString(); }, [pathname, file.name]); @@ -154,10 +154,7 @@ const FileInfoModal = ({ // ================================================================================================= // ICON MAPPING & COLORS // ================================================================================================= -const getFileIcon = ( - isFolder: boolean, - extension?: string, -): IconName => { +const getFileIcon = (isFolder: boolean, extension?: string): IconName => { if (isFolder) return "Folder"; const ext = extension?.toLowerCase(); const iconMap: Record = { @@ -214,7 +211,7 @@ const getFileIcon = ( // Enhanced color mapping for different file types const getFileColor = (isFolder: boolean, extension?: string): string => { if (isFolder) return "hsl(var(--color-folder))"; - + const ext = extension?.toLowerCase(); const colorMap: Record = { // Archives @@ -223,7 +220,7 @@ const getFileColor = (isFolder: boolean, extension?: string): string => { "7z": "hsl(var(--color-archive))", tar: "hsl(var(--color-archive))", gz: "hsl(var(--color-archive))", - + // Code files js: "hsl(var(--color-code))", ts: "hsl(var(--color-code))", @@ -237,7 +234,7 @@ const getFileColor = (isFolder: boolean, extension?: string): string => { html: "hsl(var(--color-code))", json: "hsl(var(--color-code))", xml: "hsl(var(--color-code))", - + // Media files jpg: "hsl(var(--color-media))", jpeg: "hsl(var(--color-media))", @@ -252,7 +249,7 @@ const getFileColor = (isFolder: boolean, extension?: string): string => { mp3: "hsl(var(--color-media))", wav: "hsl(var(--color-media))", flac: "hsl(var(--color-media))", - + // ISO and system files iso: "hsl(var(--color-warning))", img: "hsl(var(--color-warning))", @@ -262,7 +259,7 @@ const getFileColor = (isFolder: boolean, extension?: string): string => { rpm: "hsl(var(--color-success))", appimage: "hsl(var(--color-success))", }; - + return colorMap[ext || ""] || "hsl(var(--color-muted-foreground))"; }; @@ -360,7 +357,7 @@ export const FileItem = ({ data: file, layout }: Props) => { if (isFolder) return; const downloadUrl = new URL( `/api/download${filePath}`, - config.basePath, + config.basePath ).toString(); window.open(downloadUrl, "_blank"); }, [filePath, isFolder]); @@ -381,30 +378,35 @@ export const FileItem = ({ data: file, layout }: Props) => { >
{file.thumbnailLink && file.mimeType.includes("image") ? ( - {file.name} ) : (
-
-
{file.fileExtension && ( -
{file.fileExtension.toUpperCase()} @@ -424,18 +426,24 @@ export const FileItem = ({ data: file, layout }: Props) => { {isFolder ? ( <> -
+
DIR ) : ( <> -
+
{bytesToReadable(file.size ?? 0)} )}
- {formatDate(file.modifiedTime).split(' ')[0]} + {formatDate(file.modifiedTime).split(" ")[0]}
@@ -448,23 +456,26 @@ export const FileItem = ({ data: file, layout }: Props) => { onClick={handleClick} >
-
-
{file.fileExtension && !isFolder && ( -
{file.fileExtension.toUpperCase()} @@ -475,14 +486,17 @@ export const FileItem = ({ data: file, layout }: Props) => {
{file.name}
{!isFolder && file.mimeType && (
- {file.mimeType.split('/')[0]}/{file.mimeType.split('/')[1]} + {file.mimeType.split("/")[0]}/{file.mimeType.split("/")[1]}
)}
{!isFolder ? (
-
+
{bytesToReadable(file.size ?? 0)}
) : null} diff --git a/src/components/explorer/FileLayout.tsx b/src/components/explorer/FileLayout.tsx index 24625d1..12b8c06 100644 --- a/src/components/explorer/FileLayout.tsx +++ b/src/components/explorer/FileLayout.tsx @@ -1,21 +1,22 @@ "use client"; -import React, { useMemo, useState, useCallback } from "react"; +import React, { useCallback, useMemo, useState } from "react"; + +import { ListFiles } from "@/actions/files"; +import { useLayout } from "@/context/layoutContext"; import { toast } from "sonner"; import { type z } from "zod"; -import { FileItem } from "@/components/explorer"; -import { PageLoader } from "@/components/layout"; -import { LoadingButton } from "@/components/ui/button"; -import Icon from "@/components/ui/icon"; +import { type Schema_File } from "@/types/schema"; -import { useLayout } from "@/context/layoutContext"; -import useLoading from "@/hooks/useLoading"; import { cn } from "@/lib/utils"; -import { type Schema_File } from "@/types/schema"; +import useLoading from "@/hooks/useLoading"; -import { ListFiles } from "@/actions/files"; +import { FileItem } from "@/components/explorer"; +import { PageLoader } from "@/components/layout"; +import { LoadingButton } from "@/components/ui/button"; +import Icon from "@/components/ui/icon"; type Props = { encryptedId: string; @@ -23,128 +24,139 @@ type Props = { nextPageToken?: string; }; -const FileExplorerLayout = React.memo(({ - encryptedId, - files, - nextPageToken, -}: Props) => { - const { layout, isPending } = useLayout(); - const loading = useLoading(); - - const [filesList, setFilesList] = useState[]>(files); - const [nextToken, setNextToken] = useState(nextPageToken); - const [isLoadingMore, setLoadingMore] = useState(false); - - const onLoadMore = useCallback(async () => { - if (isLoadingMore || !nextToken) return; - - setLoadingMore(true); - try { - const data = await ListFiles({ id: encryptedId, pageToken: nextToken }); - if (!data.success) throw new Error(data.error); - - const uniqueData = [...filesList, ...data.data.files].filter( - (item, index, self) => - index === self.findIndex((i) => i.encryptedId === item.encryptedId), - ); +const FileExplorerLayout = React.memo( + ({ encryptedId, files, nextPageToken }: Props) => { + const { layout, isPending } = useLayout(); + const loading = useLoading(); - setFilesList(uniqueData); - setNextToken(data.data.nextPageToken ?? undefined); - } catch (error) { - const e = error as Error; - console.error(`[OnLoadMore] ${e.message}`); - toast.error(e.message); - } finally { - setLoadingMore(false); - } - }, [encryptedId, filesList, nextToken, isLoadingMore]); - - // Memoize the load more button - const loadMoreButton = useMemo(() => { - if (!nextToken) return null; - - return ( -
- - Load more files - -
+ const [filesList, setFilesList] = + useState[]>(files); + const [nextToken, setNextToken] = useState( + nextPageToken ); - }, [nextToken, isLoadingMore, onLoadMore]); - - // Determine if there is at least one file (not a directory) in the list - const hasFiles = filesList.some(f => !f.mimeType.includes("folder")); - - if (loading || isPending) return ; - - if (!filesList.length) { - return ( -
-
-
-
- -
-
+ const [isLoadingMore, setLoadingMore] = useState(false); + + const onLoadMore = useCallback(async () => { + if (isLoadingMore || !nextToken) return; + + setLoadingMore(true); + try { + const data = await ListFiles({ id: encryptedId, pageToken: nextToken }); + if (!data.success) throw new Error(data.error); + + const uniqueData = [...filesList, ...data.data.files].filter( + (item, index, self) => + index === self.findIndex((i) => i.encryptedId === item.encryptedId) + ); + + setFilesList(uniqueData); + setNextToken(data.data.nextPageToken ?? undefined); + } catch (error) { + const e = error as Error; + console.error(`[OnLoadMore] ${e.message}`); + toast.error(e.message); + } finally { + setLoadingMore(false); + } + }, [encryptedId, filesList, nextToken, isLoadingMore]); + + // Memoize the load more button + const loadMoreButton = useMemo(() => { + if (!nextToken) return null; + + return ( +
+ + Load more files + +
+ ); + }, [nextToken, isLoadingMore, onLoadMore]); + + // Determine if there is at least one file (not a directory) in the list + const hasFiles = filesList.some((f) => !f.mimeType.includes("folder")); + + if (loading || isPending) return ; + + if (!filesList.length) { + return ( +
+
+
+
+ +
+
+
+

+ DIRECTORY_EMPTY +

+

+ No files or directories found in current path. +
+ +

+ errno: ENOENT • status: 404 + +

-

- DIRECTORY_EMPTY -

-

- No files or directories found in current path.
- -

- errno: ENOENT • status: 404 - -

-
- ); - } + ); + } - return ( -
- {/* List Header */} - {layout === "list" && ( -
- {hasFiles && ( -
-
- + return ( +
+ {/* List Header */} + {layout === "list" && ( +
+ {hasFiles && ( +
+
+ +
+ TYPE
- TYPE -
+ )} +
NAME
+
SIZE
+
MODIFIED
+
+
+ )} + + {/* Files Grid/List */} +
NAME
-
SIZE
-
MODIFIED
-
+ > + {filesList.map((file) => ( +
+ +
+ ))}
- )} - - {/* Files Grid/List */} -
- {filesList.map((file) => ( -
- -
- ))} -
- {loadMoreButton} -
- ); -}); + {loadMoreButton} +
+ ); + } +); FileExplorerLayout.displayName = "FileExplorerLayout"; diff --git a/src/components/explorer/FileReadme.tsx b/src/components/explorer/FileReadme.tsx index 22cd467..7577fbe 100644 --- a/src/components/explorer/FileReadme.tsx +++ b/src/components/explorer/FileReadme.tsx @@ -2,12 +2,12 @@ import { useState } from "react"; +import { cn } from "@/lib/utils"; + import { Markdown } from "@/components/global"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { cn } from "@/lib/utils"; - type Props = { content: string; title: string; @@ -22,7 +22,7 @@ export default function FileReadme({ content, title }: Props) {
{title} diff --git a/src/components/global/Markdown.tsx b/src/components/global/Markdown.tsx index 9d3d80c..98bffc6 100644 --- a/src/components/global/Markdown.tsx +++ b/src/components/global/Markdown.tsx @@ -1,6 +1,7 @@ "use client"; import { useCallback, useEffect, useRef, useState } from "react"; + import ReactMarkdown from "react-markdown"; import rehypeKatex from "rehype-katex"; import rehypePrism from "rehype-prism-plus"; @@ -12,15 +13,19 @@ import remarkMath from "remark-math"; import remarkToc from "remark-toc"; import { toast } from "sonner"; -import Icon from "@/components/ui/icon"; - import { cn } from "@/lib/utils"; +import Icon from "@/components/ui/icon"; +import Image from "next/image"; + type Props = { content: string; view?: "markdown" | "raw"; className?: string; - customComponents?: Record>>; + customComponents?: Record< + string, + React.ComponentType> + >; }; export default function Markdown({ content, @@ -29,7 +34,7 @@ export default function Markdown({ customComponents, }: Props) { const [viewState, setViewState] = useState<"markdown" | "raw">( - view ?? "markdown", + view ?? "markdown" ); useEffect(() => { @@ -50,7 +55,7 @@ export default function Markdown({ ) : (
{ + img: ({ src, alt, className, width, height, ...props }) => { return ( <> - {alt} { if (typeof src === "string") { @@ -99,7 +106,7 @@ export default function Markdown({ rel={isRelative ? rel : "noreferer"} className={cn( "whitespace-pre-wrap! break-words!", - className, + className )} {...props} /> @@ -115,7 +122,7 @@ export default function Markdown({ @@ -137,7 +144,7 @@ function PreComponent(props: React.HTMLAttributes) { const codeRef = useRef(null); const [copyStatus, setCopyStatus] = useState<"idle" | "copied" | "error">( - "idle", + "idle" ); const copyTimeout = useRef(undefined); diff --git a/src/components/global/Status.tsx b/src/components/global/Status.tsx index fb67ab5..60e2118 100644 --- a/src/components/global/Status.tsx +++ b/src/components/global/Status.tsx @@ -2,10 +2,10 @@ import { type icons } from "lucide-react"; -import Icon from "@/components/ui/icon"; - import { cn } from "@/lib/utils"; +import Icon from "@/components/ui/icon"; + type Props = { icon: keyof typeof icons; iconClassName?: string; @@ -26,7 +26,7 @@ export default function Status({ "flex flex-col items-center justify-center gap-2", destructive ? "stroke-destructive text-destructive" - : "stroke-muted-foreground text-muted-foreground", + : "stroke-muted-foreground text-muted-foreground" )} > diff --git a/src/components/internal/ConfiguratorPage.Api.tsx b/src/components/internal/ConfiguratorPage.Api.tsx deleted file mode 100644 index 6e00437..0000000 --- a/src/components/internal/ConfiguratorPage.Api.tsx +++ /dev/null @@ -1,621 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { toast } from "sonner"; - -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import Icon from "@/components/ui/icon"; -import { Input } from "@/components/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Switch } from "@/components/ui/switch"; - -import { cn } from "@/lib/utils"; - -import { FormColumn, type FormProps, FormSection } from "./ConfiguratorPage"; - -export default function ApiForm({ form, onResetField }: FormProps) { - const [inputHiddenFile, setInputHiddenFile] = useState(""); - function onHiddenFileSubmit() { - if (!inputHiddenFile) { - toast.error("File name cannot be empty"); - setInputHiddenFile(""); - return; - } - const prevValue = form.watch("api.hiddenFiles"); - const value = inputHiddenFile.trim(); - if (prevValue.some((v) => v.trim() === value)) { - toast.error("File name already exists in the hidden files list"); - setInputHiddenFile(""); - return; - } - form.setValue( - "api.hiddenFiles", - [...form.watch("api.hiddenFiles"), inputHiddenFile], - { - shouldDirty: true, - }, - ); - setInputHiddenFile(""); - } - - return ( - - - ( - - { - onResetField?.("api.cache.public"); - }} - > - Public Cache - - - - - - Enable public cache for the index. - - - - )} - /> - ( - - { - onResetField?.("api.cache.staleWhileRevalidate"); - }} - > - Stale While Revalidate - - - - - - Return stale data before requesting fresh data. - - - - )} - /> - ( - - { - onResetField?.("api.cache.maxAge"); - }} - > - Max Age - - - - - - How long should the cache in browser last. - - - - )} - /> - ( - - { - onResetField?.("api.cache.sMaxAge"); - }} - > - Shared Max Age - - - - - - How long should the cache in server last. - - - - )} - /> - - - ( - - { - onResetField?.("api.rootFolder"); - }} - > - Root Folder ID - - - - - - Google Drive folder ID to be used as the root folder. - - - - )} - /> - ( - -
- { - onResetField?.("api.sharedDrive"); - form.setValue("api.isTeamDrive", false); - }} - > - Shared Drive ID - - { - form.setValue("api.isTeamDrive", value); - }} - /> -
- - - - Google Drive Shared Drive ID. - -
- )} - /> - - ( - - { - onResetField?.("api.itemsPerPage"); - }} - > - Items Per Page - - - - - - Number of items to show before pagination. - - - - )} - /> - ( - - { - onResetField?.("api.searchResult"); - }} - > - Search Result Limit - - - - - - Number of search results to show. - - - - )} - /> - - - ( - - { - onResetField?.("api.specialFile.banner"); - }} - > - Banner File - - - - - - Will be used as the banner if found in the folder. - - - - )} - /> - - ( - - { - onResetField?.("api.specialFile.readme"); - }} - > - Readme File - - - - - - Will be used as the description if found in the folder. - - - - )} - /> - - { - const watch = form.watch("api.hiddenFiles"); - - return ( - - { - onResetField?.("api.hiddenFiles"); - }} - > - Hidden Files - -
-
- {watch.length ? ( - <> -
- {watch.map((name, index) => ( - { - form.setValue( - "api.hiddenFiles", - watch.filter((_, i) => i !== index), - { - shouldDirty: true, - }, - ); - }} - > - {name} - - ))} - - Click to remove hidden file - -
- - ) : ( - - All files including special files are visible. - - )} -
- -
- setInputHiddenFile(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") { - onHiddenFileSubmit(); - } - }} - /> - -
-
- { - if ( - watch.includes(form.watch("api.specialFile.banner")) - ) { - return; - } - form.setValue("api.hiddenFiles", [ - ...watch, - form.watch("api.specialFile.banner"), - ]); - }} - > - - {watch.includes(form.watch("api.specialFile.banner")) - ? "Banner file is hidden" - : "Add banner file to the list"} - - - { - if ( - watch.includes(form.watch("api.specialFile.readme")) - ) { - return; - } - form.setValue("api.hiddenFiles", [ - ...watch, - form.watch("api.specialFile.readme"), - ]); - }} - > - - {watch.includes(form.watch("api.specialFile.readme")) - ? "Readme file is hidden" - : "Add readme file to the list"} - -
-
- - Click the badge to add special files to the hidden files list. - - -
- ); - }} - /> - - ( - - { - onResetField?.("api.proxyThumbnail"); - }} - > - Proxy Thumbnail - - - - - - Serve thumbnail through API route to avoid CORS issue. - - - - )} - /> - - ( - - { - onResetField?.("api.streamMaxSize"); - }} - > - Preview Max Size - - - { - const value = Number(e.target.value ?? "0"); - form.setValue("api.streamMaxSize", value * 1024 * 1024, { - shouldDirty: true, - }); - }} - /> - - - Maximum file size to be previewed in the browser in MB. Larger - file won't be previewed. -
- - Will count towards the deployment bandwidth usage. - {" "} - Set to 0 to disable the limit -
- -
- )} - /> - ( - - { - onResetField?.("api.maxFileSize"); - }} - > - Max File Size - - - { - const value = Number(e.target.value ?? "0"); - form.setValue("api.maxFileSize", value * 1024 * 1024, { - shouldDirty: true, - }); - }} - /> - - - Maximum file size that can be downloaded via API route. Larger - file will be using GDrive link. -
- - Will count towards the deployment bandwidth usage. - {" "} - Set to 0 to disable the limit -
- -
- )} - /> -
-
- ); -} diff --git a/src/components/internal/ConfiguratorPage.Environment.tsx b/src/components/internal/ConfiguratorPage.Environment.tsx deleted file mode 100644 index bc20737..0000000 --- a/src/components/internal/ConfiguratorPage.Environment.tsx +++ /dev/null @@ -1,177 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { toast } from "sonner"; - -import { LoadingButton } from "@/components/ui/button"; -import { - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; - -import { type PickFileResponse, pickFile } from "@/lib/configurationHelper"; - -import { GenerateServiceAccountB64 } from "@/actions/configuration"; - -import { type FormProps, FormSection } from "./ConfiguratorPage"; - -export default function EnvironmentForm({ onResetField, form }: FormProps) { - const [isLoadServiceLoading, setLoadServiceLoading] = - useState(false); - - async function onLoadServiceAccount(response: PickFileResponse) { - const id = `service-account-${Date.now()}`; - toast.loading("Waiting for file...", { - id, - duration: 0, - }); - if (!response.success) { - toast.error("Failed to load service account file", { - id, - description: response.details.length ? ( -
-            {response.details.join("\n")}
-          
- ) : undefined, - }); - setLoadServiceLoading(false); - return; - } - - toast.loading("Processing service account file", { - id, - }); - const data = await GenerateServiceAccountB64(response.data); - if (!data.success) { - toast.error("Failed to encode service account", { - id, - description: ( -
-            {data.error}
-          
- ), - }); - setLoadServiceLoading(false); - return; - } - - form.setValue("environment.GD_SERVICE_B64", data.data); - toast.success("Service account encoded", { - id, - }); - setLoadServiceLoading(false); - } - - return ( - - ( - - { - onResetField?.("environment.GD_SERVICE_B64"); - }} - > - Service Account - -
- - - - { - setLoadServiceLoading(true); - - pickFile({ - accept: ".json", - async onLoad(response) { - await onLoadServiceAccount(response); - }, - }); - }} - type="button" - > - Load JSON - -
- - Load your service account JSON file to get the base64 encoded - string. - - -
- )} - /> - ( - - { - onResetField?.("environment.ENCRYPTION_KEY"); - }} - > - Encryption Key - - - - - - Secret encryption key to protect sensitive data. - - - - )} - /> - - ( - - { - onResetField?.("environment.NEXT_PUBLIC_DOMAIN"); - }} - > - Site Domain - - - - - - The domain for the site, without the protocol. -
- Needed if you deploy outside of Vercel. -
- -
- )} - /> -
- ); -} diff --git a/src/components/internal/ConfiguratorPage.Site.tsx b/src/components/internal/ConfiguratorPage.Site.tsx deleted file mode 100644 index b2a1a29..0000000 --- a/src/components/internal/ConfiguratorPage.Site.tsx +++ /dev/null @@ -1,869 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { useMemo, useState } from "react"; -import { useFieldArray } from "react-hook-form"; -import ReactMarkdown from "react-markdown"; -import remarkBreaks from "remark-breaks"; -import { toast } from "sonner"; -import { type z } from "zod"; - -import { Button } from "@/components/ui/button"; -import { VirtualizedCombobox } from "@/components/ui/combobox.virtualized"; -import { - ResponsiveDialog, - ResponsiveDialogBody, - ResponsiveDialogClose, - ResponsiveDialogContent, - ResponsiveDialogDescription, - ResponsiveDialogFooter, - ResponsiveDialogHeader, - ResponsiveDialogTitle, - ResponsiveDialogTrigger, -} from "@/components/ui/dialog.responsive"; -import { - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import Icon, { IconNamesArray } from "@/components/ui/icon"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Separator } from "@/components/ui/separator"; -import { Textarea } from "@/components/ui/textarea"; - -import { useResponsive } from "@/context/responsiveContext"; -import { cn, formatFooterContent } from "@/lib/utils"; - -import { type Schema_App_Configuration } from "@/types/schema"; - -import { FormColumn, type FormProps, FormSection } from "./ConfiguratorPage"; - -export default function SiteForm({ form, onResetField }: FormProps) { - return ( - - ( - - { - onResetField?.("site.guideButton"); - }} - > - Internal Menu - - - - - Show internal menu on the navbar. - - - )} - /> - - ( - - { - onResetField?.("site.siteName"); - }} - > - Site Name - - - - - Site name for meta and navbar. - - - )} - /> - ( - - { - onResetField?.("site.siteNameTemplate"); - }} - > - Site Name Template - - - - - - Template for the site name.{" "} - %t for site name and{" "} - %s for page title. - - - - )} - /> - -
- - {(form.watch("site.siteNameTemplate") ?? "No template") - .replace("%t", form.watch("site.siteName") ?? "next-gdrive-index") - .replace("%s", "Page Title Goes Here")} - -
-
- ( - - { - onResetField?.("site.siteDescription"); - }} - > - Site Description - - -