Compare commits
15 Commits
nix
...
157-mirror
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6531a9325d | ||
|
|
ff44f0e537 | ||
|
|
dec34fc384 | ||
|
|
f5727daedb | ||
|
|
3857f2fd1a | ||
|
|
e951e97790 | ||
|
|
d0cade633a | ||
|
|
490059666f | ||
|
|
5852bb00f2 | ||
|
|
749ad4a694 | ||
|
|
0f752acae5 | ||
|
|
652bd220c2 | ||
|
|
9f2eaaf04e | ||
|
|
63d3f0e86c | ||
|
|
25e7d234ba |
43
.github/workflows/nix-build.yml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Nix Build and Cache
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: cachix/install-nix-action@v24
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: gitea-mirror # Your cache name
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
- name: Build package
|
||||
run: nix build --print-build-logs
|
||||
|
||||
- name: Check flake
|
||||
run: nix flake check
|
||||
|
||||
- name: Test run (dry run)
|
||||
run: |
|
||||
# Just verify the binary exists and is executable
|
||||
test -x ./result/bin/gitea-mirror
|
||||
./result/bin/gitea-mirror --version || echo "Version check skipped"
|
||||
5
.gitignore
vendored
@@ -32,8 +32,3 @@ certs/*.pem
|
||||
certs/*.cer
|
||||
!certs/README.md
|
||||
|
||||
# Nix build artifacts
|
||||
result
|
||||
result-*
|
||||
.direnv/
|
||||
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
# Nix Distribution - Ready to Use! 🎉
|
||||
|
||||
## Current Status: ✅ WORKS NOW
|
||||
|
||||
Your Nix package is **already distributable**! Users can run it directly from GitHub without any additional setup on your end.
|
||||
|
||||
## How Users Will Use It
|
||||
|
||||
### Simple: Just Run From GitHub
|
||||
|
||||
```bash
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
```
|
||||
|
||||
That's it! No releases, no CI, no infrastructure needed. It works right now.
|
||||
|
||||
---
|
||||
|
||||
## What Happens When They Run This?
|
||||
|
||||
1. **Nix fetches** your repo from GitHub
|
||||
2. **Nix reads** `flake.nix` and `flake.lock`
|
||||
3. **Nix builds** the package on their machine
|
||||
4. **Nix runs** the application
|
||||
5. **Result cached** in `/nix/store` for reuse
|
||||
|
||||
---
|
||||
|
||||
## Do You Need CI or Releases?
|
||||
|
||||
### For Basic Usage: **NO**
|
||||
Users can already use it from GitHub. No CI or releases required.
|
||||
|
||||
### For Better UX: **Recommended**
|
||||
Set up binary caching so users don't compile from source.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps (Optional but Recommended)
|
||||
|
||||
### Option 1: Add Binary Cache (5 minutes)
|
||||
|
||||
**Why:** Users download pre-built binaries instead of compiling (much faster!)
|
||||
|
||||
**How:**
|
||||
1. Create free account at https://cachix.org/
|
||||
2. Create cache named `gitea-mirror`
|
||||
3. Add GitHub secret: `CACHIX_AUTH_TOKEN`
|
||||
4. GitHub Actions workflow already created at `.github/workflows/nix-build.yml`
|
||||
5. Add to your docs:
|
||||
```bash
|
||||
# Users run once
|
||||
cachix use gitea-mirror
|
||||
|
||||
# Then they get fast binary downloads
|
||||
nix run github:RayLabsHQ/gitea-mirror
|
||||
```
|
||||
|
||||
### Option 2: Release Versioning (2 minutes)
|
||||
|
||||
**Why:** Users can pin to specific versions
|
||||
|
||||
**How:**
|
||||
```bash
|
||||
# When ready to release
|
||||
git tag v3.8.11
|
||||
git push origin v3.8.11
|
||||
|
||||
# Users can then pin to this version
|
||||
nix run github:RayLabsHQ/gitea-mirror/v3.8.11
|
||||
```
|
||||
|
||||
No additional CI needed - tags work automatically with flakes!
|
||||
|
||||
### Option 3: Submit to nixpkgs (Long Term)
|
||||
|
||||
**Why:** Maximum discoverability and trust
|
||||
|
||||
**When:** After package is stable and well-tested
|
||||
|
||||
**How:** Submit PR to https://github.com/NixOS/nixpkgs
|
||||
|
||||
---
|
||||
|
||||
## Files Created
|
||||
|
||||
### Essential (Already Working)
|
||||
- ✅ `flake.nix` - Package definition
|
||||
- ✅ `flake.lock` - Dependency lock file
|
||||
- ✅ `.envrc` - direnv integration
|
||||
|
||||
### Documentation
|
||||
- ✅ `NIX.md` - Quick reference for users
|
||||
- ✅ `docs/NIX_DEPLOYMENT.md` - Complete deployment guide
|
||||
- ✅ `docs/NIX_DISTRIBUTION.md` - Distribution guide for you (maintainer)
|
||||
- ✅ `README.md` - Updated with Nix instructions
|
||||
|
||||
### CI (Optional, Already Set Up)
|
||||
- ✅ `.github/workflows/nix-build.yml` - Builds + caches to Cachix
|
||||
|
||||
### Updated
|
||||
- ✅ `.gitignore` - Added Nix artifacts
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Your Distribution Options
|
||||
|
||||
| Setup | Time | User Experience | What You Need |
|
||||
|-------|------|----------------|---------------|
|
||||
| **Direct GitHub** | 0 min ✅ | Slow (build from source) | Nothing! Works now |
|
||||
| **+ Cachix** | 5 min | Fast (binary download) | Cachix account + token |
|
||||
| **+ Git Tags** | 2 min | Versionable | Just push tags |
|
||||
| **+ nixpkgs** | Hours | Official/Trusted | PR review process |
|
||||
|
||||
**Recommendation:** Start with Direct GitHub (already works!), add Cachix this week for better UX.
|
||||
|
||||
---
|
||||
|
||||
## Testing Your Distribution
|
||||
|
||||
You can test it right now:
|
||||
|
||||
```bash
|
||||
# Test direct GitHub usage
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Test with specific commit
|
||||
nix run github:RayLabsHQ/gitea-mirror/$(git rev-parse HEAD)
|
||||
|
||||
# Validate flake
|
||||
nix flake check
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Documentation Locations
|
||||
|
||||
Users will find instructions in:
|
||||
1. **README.md** - Installation section (already updated)
|
||||
2. **NIX.md** - Quick reference
|
||||
3. **docs/NIX_DEPLOYMENT.md** - Detailed guide
|
||||
|
||||
All docs include the correct commands with experimental features flags.
|
||||
|
||||
---
|
||||
|
||||
## When to Release New Versions
|
||||
|
||||
### For Git Tag Releases:
|
||||
```bash
|
||||
# 1. Update version in package.json
|
||||
vim package.json
|
||||
|
||||
# 2. Update version in flake.nix (line 17)
|
||||
vim flake.nix # version = "3.8.12";
|
||||
|
||||
# 3. Commit and tag
|
||||
git add package.json flake.nix
|
||||
git commit -m "chore: bump version to v3.8.12"
|
||||
git tag v3.8.12
|
||||
git push origin main
|
||||
git push origin v3.8.12
|
||||
```
|
||||
|
||||
Users can then use: `nix run github:RayLabsHQ/gitea-mirror/v3.8.12`
|
||||
|
||||
### No Release Needed For:
|
||||
- Bug fixes
|
||||
- Small changes
|
||||
- Continuous updates
|
||||
|
||||
Users can always use latest from main: `nix run github:RayLabsHQ/gitea-mirror`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**✅ Ready to distribute RIGHT NOW**
|
||||
- Just commit and push your `flake.nix`
|
||||
- Users can run directly from GitHub
|
||||
- No CI, releases, or infrastructure required
|
||||
|
||||
**🚀 Recommended next: Add Cachix (5 minutes)**
|
||||
- Much better user experience
|
||||
- Workflow already created
|
||||
- Free for public projects
|
||||
|
||||
**📦 Optional later: Submit to nixpkgs**
|
||||
- Maximum discoverability
|
||||
- Official Nix repository
|
||||
- Do this once package is stable
|
||||
|
||||
See `docs/NIX_DISTRIBUTION.md` for complete details!
|
||||
20
Dockerfile
@@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1.4
|
||||
|
||||
FROM oven/bun:1.2.23-alpine AS base
|
||||
FROM oven/bun:1.3.1-alpine AS base
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache libc6-compat python3 make g++ gcc wget sqlite openssl ca-certificates
|
||||
|
||||
@@ -15,9 +15,9 @@ FROM deps AS builder
|
||||
COPY . .
|
||||
RUN bun run build
|
||||
RUN mkdir -p dist/scripts && \
|
||||
for script in scripts/*.ts; do \
|
||||
bun build "$script" --target=bun --outfile=dist/scripts/$(basename "${script%.ts}.js"); \
|
||||
done
|
||||
for script in scripts/*.ts; do \
|
||||
bun build "$script" --target=bun --outfile=dist/scripts/$(basename "${script%.ts}.js"); \
|
||||
done
|
||||
|
||||
# ----------------------------
|
||||
FROM deps AS pruner
|
||||
@@ -40,12 +40,12 @@ ENV DATABASE_URL=file:data/gitea-mirror.db
|
||||
|
||||
# Create directories and setup permissions
|
||||
RUN mkdir -p /app/certs && \
|
||||
chmod +x ./docker-entrypoint.sh && \
|
||||
mkdir -p /app/data && \
|
||||
addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 gitea-mirror && \
|
||||
chown -R gitea-mirror:nodejs /app/data && \
|
||||
chown -R gitea-mirror:nodejs /app/certs
|
||||
chmod +x ./docker-entrypoint.sh && \
|
||||
mkdir -p /app/data && \
|
||||
addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 gitea-mirror && \
|
||||
chown -R gitea-mirror:nodejs /app/data && \
|
||||
chown -R gitea-mirror:nodejs /app/certs
|
||||
|
||||
USER gitea-mirror
|
||||
|
||||
|
||||
189
NIX.md
@@ -1,189 +0,0 @@
|
||||
# Nix Deployment Quick Reference
|
||||
|
||||
## TL;DR
|
||||
|
||||
```bash
|
||||
# From GitHub (no clone needed!)
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Or from local clone
|
||||
nix run --extra-experimental-features 'nix-command flakes' .#gitea-mirror
|
||||
```
|
||||
|
||||
Secrets auto-generate, database auto-initializes, and the web UI starts at http://localhost:4321.
|
||||
|
||||
**Note:** If you have flakes enabled in your nix config, you can omit `--extra-experimental-features 'nix-command flakes'`
|
||||
|
||||
---
|
||||
|
||||
## Installation Options
|
||||
|
||||
### 1. Run Without Installing (from GitHub)
|
||||
```bash
|
||||
# Latest version from main branch
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Pin to specific version
|
||||
nix run github:RayLabsHQ/gitea-mirror/v3.8.11
|
||||
```
|
||||
|
||||
### 2. Install to Profile
|
||||
```bash
|
||||
# Install from GitHub
|
||||
nix profile install --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Run the installed binary
|
||||
gitea-mirror
|
||||
```
|
||||
|
||||
### 3. Use Local Clone
|
||||
```bash
|
||||
# Clone and run
|
||||
git clone https://github.com/RayLabsHQ/gitea-mirror.git
|
||||
cd gitea-mirror
|
||||
nix run --extra-experimental-features 'nix-command flakes' .#gitea-mirror
|
||||
```
|
||||
|
||||
### 4. NixOS System Service
|
||||
```nix
|
||||
# configuration.nix
|
||||
{
|
||||
inputs.gitea-mirror.url = "github:RayLabsHQ/gitea-mirror";
|
||||
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
betterAuthUrl = "https://mirror.example.com"; # For production
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Development (Local Clone)
|
||||
```bash
|
||||
nix develop --extra-experimental-features 'nix-command flakes'
|
||||
# or
|
||||
direnv allow # Handles experimental features automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enable Flakes Permanently (Recommended)
|
||||
|
||||
To avoid typing `--extra-experimental-features` every time, add to `~/.config/nix/nix.conf`:
|
||||
```
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Gets Auto-Generated?
|
||||
|
||||
On first run, the wrapper automatically:
|
||||
|
||||
1. Creates `~/.local/share/gitea-mirror/` (or `$DATA_DIR`)
|
||||
2. Generates `BETTER_AUTH_SECRET` → `.better_auth_secret`
|
||||
3. Generates `ENCRYPTION_SECRET` → `.encryption_secret`
|
||||
4. Initializes SQLite database
|
||||
5. Runs startup recovery and repair scripts
|
||||
6. Starts the application
|
||||
|
||||
---
|
||||
|
||||
## Key Commands
|
||||
|
||||
```bash
|
||||
# Database management
|
||||
gitea-mirror-db init # Initialize database
|
||||
gitea-mirror-db check # Health check
|
||||
gitea-mirror-db fix # Fix issues
|
||||
|
||||
# Development (add --extra-experimental-features 'nix-command flakes' if needed)
|
||||
nix develop # Enter dev shell
|
||||
nix build # Build package
|
||||
nix flake check # Validate flake
|
||||
nix flake update # Update dependencies
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All vars from `docker-compose.alt.yml` are supported:
|
||||
|
||||
```bash
|
||||
DATA_DIR="$HOME/.local/share/gitea-mirror"
|
||||
PORT=4321
|
||||
HOST="0.0.0.0"
|
||||
BETTER_AUTH_URL="http://localhost:4321"
|
||||
|
||||
# Secrets (auto-generated if not set)
|
||||
BETTER_AUTH_SECRET=auto-generated
|
||||
ENCRYPTION_SECRET=auto-generated
|
||||
|
||||
# Concurrency (for perfect ordering, set both to 1)
|
||||
MIRROR_ISSUE_CONCURRENCY=3
|
||||
MIRROR_PULL_REQUEST_CONCURRENCY=5
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NixOS Module Options
|
||||
|
||||
```nix
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
package = ...; # Override package
|
||||
dataDir = "/var/lib/gitea-mirror"; # Data location
|
||||
user = "gitea-mirror"; # Service user
|
||||
group = "gitea-mirror"; # Service group
|
||||
host = "0.0.0.0"; # Bind address
|
||||
port = 4321; # Listen port
|
||||
betterAuthUrl = "http://..."; # External URL
|
||||
betterAuthTrustedOrigins = "..."; # CORS origins
|
||||
mirrorIssueConcurrency = 3; # Concurrency
|
||||
mirrorPullRequestConcurrency = 5; # Concurrency
|
||||
environmentFile = null; # Optional secrets file
|
||||
openFirewall = true; # Open firewall
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Docker vs Nix
|
||||
|
||||
| Feature | Docker | Nix |
|
||||
|---------|--------|-----|
|
||||
| **Config Required** | BETTER_AUTH_SECRET | None (auto-generated) |
|
||||
| **Startup** | `docker-compose up` | `nix run .#gitea-mirror` |
|
||||
| **Service** | Docker daemon | systemd (NixOS) |
|
||||
| **Updates** | `docker pull` | `nix flake update` |
|
||||
| **Reproducible** | Image-based | Hash-based |
|
||||
|
||||
---
|
||||
|
||||
## Full Documentation
|
||||
|
||||
- **[docs/NIX_DEPLOYMENT.md](docs/NIX_DEPLOYMENT.md)** - Complete deployment guide
|
||||
- NixOS module configuration
|
||||
- Home Manager integration
|
||||
- Production deployment examples
|
||||
- Migration from Docker
|
||||
- Troubleshooting guide
|
||||
|
||||
- **[docs/NIX_DISTRIBUTION.md](docs/NIX_DISTRIBUTION.md)** - Distribution guide for maintainers
|
||||
- How users consume the package
|
||||
- Setting up binary cache (Cachix)
|
||||
- Releasing new versions
|
||||
- Submitting to nixpkgs
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Zero-config deployment** - Runs immediately without setup
|
||||
- **Auto-secret generation** - Secure secrets created and persisted
|
||||
- **Startup recovery** - Handles interrupted jobs automatically
|
||||
- **Graceful shutdown** - Proper signal handling
|
||||
- **Health checks** - Built-in monitoring support
|
||||
- **Security hardening** - NixOS module includes systemd protections
|
||||
- **Docker parity** - Same behavior as `docker-compose.alt.yml`
|
||||
32
README.md
@@ -150,38 +150,6 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/Proxmo
|
||||
|
||||
See the [Proxmox VE Community Scripts](https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror) for more details.
|
||||
|
||||
### Nix/NixOS
|
||||
|
||||
Zero-configuration deployment with Nix:
|
||||
|
||||
```bash
|
||||
# Run immediately - no setup needed!
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Or build and run locally
|
||||
nix build --extra-experimental-features 'nix-command flakes'
|
||||
./result/bin/gitea-mirror
|
||||
|
||||
# Or install to profile
|
||||
nix profile install --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
gitea-mirror
|
||||
```
|
||||
|
||||
**NixOS users** - add to your configuration:
|
||||
```nix
|
||||
{
|
||||
inputs.gitea-mirror.url = "github:RayLabsHQ/gitea-mirror";
|
||||
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
betterAuthUrl = "https://mirror.example.com";
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Secrets auto-generate, database auto-initializes. See [NIX.md](NIX.md) for quick reference or [docs/NIX_DEPLOYMENT.md](docs/NIX_DEPLOYMENT.md) for full documentation.
|
||||
|
||||
### Manual Installation
|
||||
|
||||
```bash
|
||||
|
||||
274
bun.lock
@@ -5,37 +5,37 @@
|
||||
"name": "gitea-mirror",
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.5",
|
||||
"@astrojs/mdx": "4.3.7",
|
||||
"@astrojs/mdx": "4.3.10",
|
||||
"@astrojs/node": "9.5.0",
|
||||
"@astrojs/react": "^4.4.0",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@better-auth/sso": "1.4.0-beta.12",
|
||||
"@octokit/plugin-throttling": "^11.0.2",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@octokit/plugin-throttling": "^11.0.3",
|
||||
"@octokit/rest": "^22.0.1",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-avatar": "^1.1.11",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-hover-card": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-progress": "^1.1.8",
|
||||
"@radix-ui/react-radio-group": "^1.3.8",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.2.6",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@tailwindcss/vite": "^4.1.15",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tanstack/react-virtual": "^3.13.12",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"astro": "^5.14.8",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"astro": "^5.15.4",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"better-auth": "1.4.0-beta.13",
|
||||
"buffer": "^6.0.3",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
@@ -43,17 +43,17 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-orm": "^0.44.6",
|
||||
"drizzle-orm": "^0.44.7",
|
||||
"fuse.js": "^7.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.546.0",
|
||||
"lucide-react": "^0.553.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.15",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3",
|
||||
"uuid": "^13.0.0",
|
||||
@@ -64,11 +64,11 @@
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/bcryptjs": "^3.0.0",
|
||||
"@types/bun": "^1.3.0",
|
||||
"@types/bun": "^1.3.1",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@vitejs/plugin-react": "^5.0.4",
|
||||
"drizzle-kit": "^0.31.5",
|
||||
"@vitejs/plugin-react": "^5.1.0",
|
||||
"drizzle-kit": "^0.31.6",
|
||||
"jsdom": "^26.1.0",
|
||||
"tsx": "^4.20.6",
|
||||
"vitest": "^3.2.4",
|
||||
@@ -76,8 +76,8 @@
|
||||
},
|
||||
},
|
||||
"overrides": {
|
||||
"@esbuild-kit/esm-loader": "npm:tsx@^4.20.5",
|
||||
"devalue": "^5.3.2",
|
||||
"@esbuild-kit/esm-loader": "npm:tsx@^4.20.6",
|
||||
"devalue": "^5.4.2",
|
||||
},
|
||||
"packages": {
|
||||
"@adobe/css-tools": ["@adobe/css-tools@4.4.3", "", {}, "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA=="],
|
||||
@@ -96,13 +96,13 @@
|
||||
|
||||
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.8", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.4", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.13.0", "smol-toml": "^1.4.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-uFNyFWadnULWK2cOw4n0hLKeu+xaVWeuECdP10cQ3K2fkybtTlhb7J7TcScdjmS8Yps7oje9S/ehYMfZrhrgCg=="],
|
||||
|
||||
"@astrojs/mdx": ["@astrojs/mdx@4.3.7", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.8", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "kleur": "^4.1.5", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-5SRmvMyT/UMWaU2eoD+htnXtE2mUZZEH2K/nEzhuEy+iCsOSuS/DUry59WuKUJRQETi1mgJFdNR4dZLJHYVuRA=="],
|
||||
"@astrojs/mdx": ["@astrojs/mdx@4.3.10", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.8", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "picocolors": "^1.1.1", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-2T5+XIr7PMqMeXhRofXY5NlY4lA0Km+wkfsqmr9lq5KXUHpGlKPQ9dlDZJP9E/CtljJyEBNS17zq66LrIJ1tiQ=="],
|
||||
|
||||
"@astrojs/node": ["@astrojs/node@9.5.0", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.4", "send": "^1.2.0", "server-destroy": "^1.0.1" }, "peerDependencies": { "astro": "^5.14.3" } }, "sha512-x1whLIatmCefaqJA8FjfI+P6FStF+bqmmrib0OUGM1M3cZhAXKLgPx6UF2AzQ3JgpXgCWYM24MHtraPvZhhyLQ=="],
|
||||
|
||||
"@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
|
||||
|
||||
"@astrojs/react": ["@astrojs/react@4.4.0", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.3.6" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-RzblkVImAFdV1C0AWsSWzS70Z0FMtW2p0XXkNYu3QePfyVJta3JIy8m8jY8271etaCZtpFjsE2UaiHGZIBm6nw=="],
|
||||
"@astrojs/react": ["@astrojs/react@4.4.2", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.4.1" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ=="],
|
||||
|
||||
"@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="],
|
||||
|
||||
@@ -326,29 +326,29 @@
|
||||
|
||||
"@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
|
||||
|
||||
"@octokit/core": ["@octokit/core@7.0.2", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.1", "@octokit/request": "^10.0.2", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g=="],
|
||||
"@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="],
|
||||
|
||||
"@octokit/endpoint": ["@octokit/endpoint@11.0.0", "", { "dependencies": { "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ=="],
|
||||
"@octokit/endpoint": ["@octokit/endpoint@11.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ=="],
|
||||
|
||||
"@octokit/graphql": ["@octokit/graphql@9.0.1", "", { "dependencies": { "@octokit/request": "^10.0.2", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg=="],
|
||||
"@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="],
|
||||
|
||||
"@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="],
|
||||
"@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||
|
||||
"@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.0.1", "", { "dependencies": { "@octokit/types": "^14.1.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-m1KvHlueScy4mQJWvFDCxFBTIdXS0K1SgFGLmqHyX90mZdCIv6gWBbKRhatxRjhGlONuTK/hztYdaqrTXcFZdQ=="],
|
||||
"@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@14.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw=="],
|
||||
|
||||
"@octokit/plugin-request-log": ["@octokit/plugin-request-log@6.0.0", "", { "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q=="],
|
||||
|
||||
"@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@16.0.0", "", { "dependencies": { "@octokit/types": "^14.1.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g=="],
|
||||
"@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@17.0.0", "", { "dependencies": { "@octokit/types": "^16.0.0" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw=="],
|
||||
|
||||
"@octokit/plugin-throttling": ["@octokit/plugin-throttling@11.0.2", "", { "dependencies": { "@octokit/types": "^15.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^7.0.0" } }, "sha512-ntNIig4zZhQVOZF4fG9Wt8QCoz9ehb+xnlUwp74Ic2ANChCk8oKmRwV9zDDCtrvU1aERIOvtng8wsalEX7Jk5Q=="],
|
||||
"@octokit/plugin-throttling": ["@octokit/plugin-throttling@11.0.3", "", { "dependencies": { "@octokit/types": "^16.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": "^7.0.0" } }, "sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg=="],
|
||||
|
||||
"@octokit/request": ["@octokit/request@10.0.2", "", { "dependencies": { "@octokit/endpoint": "^11.0.0", "@octokit/request-error": "^7.0.0", "@octokit/types": "^14.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-iYj4SJG/2bbhh+iIpFmG5u49DtJ4lipQ+aPakjL9OKpsGY93wM8w06gvFbEQxcMsZcCvk5th5KkIm2m8o14aWA=="],
|
||||
"@octokit/request": ["@octokit/request@10.0.6", "", { "dependencies": { "@octokit/endpoint": "^11.0.2", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "fast-content-type-parse": "^3.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-FO+UgZCUu+pPnZAR+iKdUt64kPE7QW7ciqpldaMXaNzixz5Jld8dJ31LAUewk0cfSRkNSRKyqG438ba9c/qDlQ=="],
|
||||
|
||||
"@octokit/request-error": ["@octokit/request-error@7.0.0", "", { "dependencies": { "@octokit/types": "^14.0.0" } }, "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg=="],
|
||||
"@octokit/request-error": ["@octokit/request-error@7.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-U8piOROoQQUyExw5c6dTkU3GKxts5/ERRThIauNL7yaRoeXW0q/5bgHWT7JfWBw1UyrbK8ERId2wVkcB32n0uQ=="],
|
||||
|
||||
"@octokit/rest": ["@octokit/rest@22.0.0", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.1", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0" } }, "sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA=="],
|
||||
"@octokit/rest": ["@octokit/rest@22.0.1", "", { "dependencies": { "@octokit/core": "^7.0.6", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-request-log": "^6.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0" } }, "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw=="],
|
||||
|
||||
"@octokit/types": ["@octokit/types@15.0.0", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ=="],
|
||||
"@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||
|
||||
"@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="],
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
|
||||
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
|
||||
|
||||
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
|
||||
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.11", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q=="],
|
||||
|
||||
"@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
|
||||
|
||||
@@ -398,7 +398,7 @@
|
||||
|
||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
|
||||
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
|
||||
|
||||
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
||||
|
||||
@@ -412,7 +412,7 @@
|
||||
|
||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="],
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.8", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA=="],
|
||||
|
||||
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
|
||||
|
||||
@@ -422,9 +422,9 @@
|
||||
|
||||
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
|
||||
|
||||
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
||||
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="],
|
||||
|
||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="],
|
||||
|
||||
"@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
|
||||
|
||||
@@ -454,7 +454,7 @@
|
||||
|
||||
"@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.38", "", {}, "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw=="],
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.43", "", {}, "sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ=="],
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||
|
||||
@@ -498,17 +498,17 @@
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.41.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw=="],
|
||||
|
||||
"@shikijs/core": ["@shikijs/core@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L1Safnhra3tX/oJK5kYHaWmLEBJi1irASwewzY3taX5ibyXyMkkSDZlq01qigjryOBwrXSdFgTiZ3ryzSNeu7Q=="],
|
||||
"@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="],
|
||||
|
||||
"@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Nm3/azSsaVS7hk6EwtHEnTythjQfwvrO5tKqMlaH9TwG1P+PNaR8M0EAKZ+GaH2DFwvcr4iSfTveyxMIvXEHMw=="],
|
||||
"@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="],
|
||||
|
||||
"@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-hozwnFHsLvujK4/CPVHNo3Bcg2EsnG8krI/ZQ2FlBlCRpPZW4XAEQmEwqegJsypsTAN9ehu2tEYe30lYKSZW/w=="],
|
||||
"@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="],
|
||||
|
||||
"@shikijs/langs": ["@shikijs/langs@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2" } }, "sha512-bVx5PfuZHDSHoBal+KzJZGheFuyH4qwwcwG/n+MsWno5cTlKmaNtTsGzJpHYQ8YPbB5BdEdKU1rga5/6JGY8ww=="],
|
||||
"@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="],
|
||||
|
||||
"@shikijs/themes": ["@shikijs/themes@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2" } }, "sha512-fTR3QAgnwYpfGczpIbzPjlRnxyONJOerguQv1iwpyQZ9QXX4qy/XFQqXlf17XTsorxnHoJGbH/LXBvwtqDsF5A=="],
|
||||
"@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="],
|
||||
|
||||
"@shikijs/types": ["@shikijs/types@3.12.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-K5UIBzxCyv0YoxN3LMrKB9zuhp1bV+LgewxuVwHdl4Gz5oePoUFrr9EfgJlGlDeXCU1b/yhdnXeuRvAnz8HN8Q=="],
|
||||
"@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
|
||||
|
||||
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
|
||||
|
||||
@@ -518,35 +518,35 @@
|
||||
|
||||
"@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="],
|
||||
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.15", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.0", "lightningcss": "1.30.2", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.15" } }, "sha512-HF4+7QxATZWY3Jr8OlZrBSXmwT3Watj0OogeDvdUY/ByXJHQ+LBtqA2brDb3sBxYslIFx6UP94BJ4X6a4L9Bmw=="],
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.17", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="],
|
||||
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.15", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.15", "@tailwindcss/oxide-darwin-arm64": "4.1.15", "@tailwindcss/oxide-darwin-x64": "4.1.15", "@tailwindcss/oxide-freebsd-x64": "4.1.15", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.15", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.15", "@tailwindcss/oxide-linux-arm64-musl": "4.1.15", "@tailwindcss/oxide-linux-x64-gnu": "4.1.15", "@tailwindcss/oxide-linux-x64-musl": "4.1.15", "@tailwindcss/oxide-wasm32-wasi": "4.1.15", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.15", "@tailwindcss/oxide-win32-x64-msvc": "4.1.15" } }, "sha512-krhX+UOOgnsUuks2SR7hFafXmLQrKxB4YyRTERuCE59JlYL+FawgaAlSkOYmDRJdf1Q+IFNDMl9iRnBW7QBDfQ=="],
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.17", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.17", "@tailwindcss/oxide-darwin-arm64": "4.1.17", "@tailwindcss/oxide-darwin-x64": "4.1.17", "@tailwindcss/oxide-freebsd-x64": "4.1.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", "@tailwindcss/oxide-linux-x64-musl": "4.1.17", "@tailwindcss/oxide-wasm32-wasi": "4.1.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA=="],
|
||||
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.15", "", { "os": "android", "cpu": "arm64" }, "sha512-TkUkUgAw8At4cBjCeVCRMc/guVLKOU1D+sBPrHt5uVcGhlbVKxrCaCW9OKUIBv1oWkjh4GbunD/u/Mf0ql6kEA=="],
|
||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.17", "", { "os": "android", "cpu": "arm64" }, "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xt5XEJpn2piMSfvd1UFN6jrWXyaKCwikP4Pidcf+yfHTSzSpYhG3dcMktjNkQO3JiLCp+0bG0HoWGvz97K162w=="],
|
||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg=="],
|
||||
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-TnWaxP6Bx2CojZEXAV2M01Yl13nYPpp0EtGpUrY+LMciKfIXiLL2r/SiSRpagE5Fp2gX+rflp/Os1VJDAyqymg=="],
|
||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog=="],
|
||||
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.15", "", { "os": "freebsd", "cpu": "x64" }, "sha512-quISQDWqiB6Cqhjc3iWptXVZHNVENsWoI77L1qgGEHNIdLDLFnw3/AfY7DidAiiCIkGX/MjIdB3bbBZR/G2aJg=="],
|
||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.17", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.15", "", { "os": "linux", "cpu": "arm" }, "sha512-ObG76+vPlab65xzVUQbExmDU9FIeYLQ5k2LrQdR2Ud6hboR+ZobXpDoKEYXf/uOezOfIYmy2Ta3w0ejkTg9yxg=="],
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17", "", { "os": "linux", "cpu": "arm" }, "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-4WbBacRmk43pkb8/xts3wnOZMDKsPFyEH/oisCm2q3aLZND25ufvJKcDUpAu0cS+CBOL05dYa8D4U5OWECuH/Q=="],
|
||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-AbvmEiteEj1nf42nE8skdHv73NoR+EwXVSgPY6l39X12Ex8pzOwwfi3Kc8GAmjsnsaDEbk+aj9NyL3UeyHcTLg=="],
|
||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.15", "", { "os": "linux", "cpu": "x64" }, "sha512-+rzMVlvVgrXtFiS+ES78yWgKqpThgV19ISKD58Ck+YO5pO5KjyxLt7AWKsWMbY0R9yBDC82w6QVGz837AKQcHg=="],
|
||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.17", "", { "os": "linux", "cpu": "x64" }, "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ=="],
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.15", "", { "os": "linux", "cpu": "x64" }, "sha512-fPdEy7a8eQN9qOIK3Em9D3TO1z41JScJn8yxl/76mp4sAXFDfV4YXxsiptJcOwy6bGR+70ZSwFIZhTXzQeqwQg=="],
|
||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.17", "", { "os": "linux", "cpu": "x64" }, "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.15", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-sJ4yd6iXXdlgIMfIBXuVGp/NvmviEoMVWMOAGxtxhzLPp9LOj5k0pMEMZdjeMCl4C6Up+RM8T3Zgk+BMQ0bGcQ=="],
|
||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.17", "", { "dependencies": { "@emnapi/core": "^1.6.0", "@emnapi/runtime": "^1.6.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-sJGE5faXnNQ1iXeqmRin7Ds/ru2fgCiaQZQQz3ZGIDtvbkeV85rAZ0QJFMDg0FrqsffZG96H1U9AQlNBRLsHVg=="],
|
||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A=="],
|
||||
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.15", "", { "os": "win32", "cpu": "x64" }, "sha512-NLeHE7jUV6HcFKS504bpOohyi01zPXi2PXmjFfkzTph8xRxDdxkRsXm/xDO5uV5K3brrE1cCwbUYmFUSHR3u1w=="],
|
||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.17", "", { "os": "win32", "cpu": "x64" }, "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw=="],
|
||||
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.15", "", { "dependencies": { "@tailwindcss/node": "4.1.15", "@tailwindcss/oxide": "4.1.15", "tailwindcss": "4.1.15" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-B6s60MZRTUil+xKoZoGe6i0Iar5VuW+pmcGlda2FX+guDuQ1G1sjiIy1W0frneVpeL/ZjZ4KEgWZHNrIm++2qA=="],
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.17", "", { "dependencies": { "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "tailwindcss": "4.1.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA=="],
|
||||
|
||||
"@tanstack/react-virtual": ["@tanstack/react-virtual@3.13.12", "", { "dependencies": { "@tanstack/virtual-core": "3.13.12" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA=="],
|
||||
|
||||
@@ -570,7 +570,7 @@
|
||||
|
||||
"@types/bcryptjs": ["@types/bcryptjs@3.0.0", "", { "dependencies": { "bcryptjs": "*" } }, "sha512-WRZOuCuaz8UcZZE4R5HXTco2goQSI2XxjGY3hbM/xDvwmqFWd4ivooImsMx65OKM6CtNKbnZ5YL+YwAwK7c1dg=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="],
|
||||
"@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="],
|
||||
|
||||
"@types/canvas-confetti": ["@types/canvas-confetti@1.9.0", "", {}, "sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg=="],
|
||||
|
||||
@@ -610,7 +610,7 @@
|
||||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.0.4", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.38", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA=="],
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.0", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.43", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew=="],
|
||||
|
||||
"@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
|
||||
|
||||
@@ -682,7 +682,7 @@
|
||||
|
||||
"astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
|
||||
|
||||
"astro": ["astro@5.14.8", "", { "dependencies": { "@astrojs/compiler": "^2.12.2", "@astrojs/internal-helpers": "0.7.4", "@astrojs/markdown-remark": "6.3.8", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^3.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.2.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.1", "deterministic-object-hash": "^2.0.2", "devalue": "^5.3.2", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.18", "magicast": "^0.3.5", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "package-manager-detector": "^1.3.0", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.2", "shiki": "^3.12.0", "smol-toml": "^1.4.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.6.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.0", "vfile": "^6.0.3", "vite": "^6.3.6", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.24.6", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-nKqCLs7BFvGQL9QWQOUqxHhlHtV0UMLXz1ANJygozvjcexBWS7FYkWI2LzRPMNYmbW4msIWNWnX2RvLdvI5Cnw=="],
|
||||
"astro": ["astro@5.15.4", "", { "dependencies": { "@astrojs/compiler": "^2.12.2", "@astrojs/internal-helpers": "0.7.4", "@astrojs/markdown-remark": "6.3.8", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^3.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.2.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.1", "deterministic-object-hash": "^2.0.2", "devalue": "^5.3.2", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "magic-string": "^0.30.18", "magicast": "^0.3.5", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "package-manager-detector": "^1.3.0", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.2", "shiki": "^3.12.0", "smol-toml": "^1.4.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.6.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.0", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.24.6", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-0g/68hLHEJZF2nYUcZM5O0kOnzCsCIf8eA9+0jfBAxp4ycujrIHRgIOdZCFKL9GoTsn8AypWbziypH5aEIF+aA=="],
|
||||
|
||||
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
|
||||
|
||||
@@ -694,7 +694,7 @@
|
||||
|
||||
"basic-auth": ["basic-auth@2.0.1", "", { "dependencies": { "safe-buffer": "5.1.2" } }, "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg=="],
|
||||
|
||||
"bcryptjs": ["bcryptjs@3.0.2", "", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog=="],
|
||||
"bcryptjs": ["bcryptjs@3.0.3", "", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g=="],
|
||||
|
||||
"before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
|
||||
|
||||
@@ -702,12 +702,6 @@
|
||||
|
||||
"better-call": ["better-call@1.0.24", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-iGqL29cstPp4xLD2MjKL1EmyAqQHjYS+cBMt4W27rPs3vf+kuqkVPA0NYaf7JciBOzVsJdNj4cbZWXC5TardWQ=="],
|
||||
|
||||
"better-sqlite3": ["better-sqlite3@12.4.1", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ=="],
|
||||
|
||||
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
|
||||
|
||||
"bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
|
||||
|
||||
"body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="],
|
||||
|
||||
"bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
|
||||
@@ -724,7 +718,7 @@
|
||||
|
||||
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
|
||||
"bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="],
|
||||
|
||||
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||
|
||||
@@ -758,8 +752,6 @@
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
|
||||
|
||||
"ci-info": ["ci-info@4.3.0", "", {}, "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ=="],
|
||||
|
||||
"class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
|
||||
@@ -822,12 +814,8 @@
|
||||
|
||||
"decode-named-character-reference": ["decode-named-character-reference@1.1.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w=="],
|
||||
|
||||
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
|
||||
|
||||
"deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
|
||||
|
||||
"deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="],
|
||||
|
||||
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
|
||||
|
||||
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||
@@ -844,7 +832,7 @@
|
||||
|
||||
"deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="],
|
||||
|
||||
"devalue": ["devalue@5.3.2", "", {}, "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw=="],
|
||||
"devalue": ["devalue@5.4.2", "", {}, "sha512-MwPZTKEPK2k8Qgfmqrd48ZKVvzSQjgW0lXLxiIBA8dQjtf/6mw6pggHNLcyDKyf+fI6eXxlQwPsfaCMTU5U+Bw=="],
|
||||
|
||||
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
|
||||
|
||||
@@ -858,9 +846,9 @@
|
||||
|
||||
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
|
||||
|
||||
"drizzle-kit": ["drizzle-kit@0.31.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-+CHgPFzuoTQTt7cOYCV6MOw2w8vqEn/ap1yv4bpZOWL03u7rlVRQhUY0WYT3rHsgVTXwYQDZaSUJSQrMBUKuWg=="],
|
||||
"drizzle-kit": ["drizzle-kit@0.31.6", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-/B4e/4pwnx25QwD5xXgdpo1S+077a2VZdosXbItE/oNmUgQwZydGDz9qJYmnQl/b+5IX0rLfwRhrPnroGtrg8Q=="],
|
||||
|
||||
"drizzle-orm": ["drizzle-orm@0.44.6", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-uy6uarrrEOc9K1u5/uhBFJbdF5VJ5xQ/Yzbecw3eAYOunv5FDeYkR2m8iitocdHBOHbvorviKOW5GVw0U1j4LQ=="],
|
||||
"drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="],
|
||||
|
||||
"dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="],
|
||||
|
||||
@@ -878,8 +866,6 @@
|
||||
|
||||
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||
|
||||
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="],
|
||||
|
||||
"entities": ["entities@6.0.0", "", {}, "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw=="],
|
||||
@@ -924,8 +910,6 @@
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
|
||||
|
||||
"expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
|
||||
|
||||
"expect-type": ["expect-type@1.2.1", "", {}, "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw=="],
|
||||
|
||||
"express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="],
|
||||
@@ -946,8 +930,6 @@
|
||||
|
||||
"fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
|
||||
|
||||
"file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="],
|
||||
@@ -962,8 +944,6 @@
|
||||
|
||||
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||
|
||||
"fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
@@ -984,8 +964,6 @@
|
||||
|
||||
"get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="],
|
||||
|
||||
"github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
|
||||
|
||||
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
@@ -1052,8 +1030,6 @@
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
|
||||
|
||||
"inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="],
|
||||
|
||||
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||
@@ -1164,7 +1140,7 @@
|
||||
|
||||
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"lucide-react": ["lucide-react@0.546.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ=="],
|
||||
"lucide-react": ["lucide-react@0.553.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-BRgX5zrWmNy/lkVAe0dXBgd7XQdZ3HTf+Hwe3c9WK6dqgnj9h+hxV+MDncM88xDWlCq27+TKvHGE70ViODNILw=="],
|
||||
|
||||
"lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="],
|
||||
|
||||
@@ -1300,14 +1276,8 @@
|
||||
|
||||
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||
|
||||
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||
|
||||
"min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
|
||||
|
||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
|
||||
"mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
|
||||
|
||||
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
@@ -1318,8 +1288,6 @@
|
||||
|
||||
"nanostores": ["nanostores@1.0.1", "", {}, "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw=="],
|
||||
|
||||
"napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="],
|
||||
|
||||
"negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||
|
||||
"neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
|
||||
@@ -1328,8 +1296,6 @@
|
||||
|
||||
"nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="],
|
||||
|
||||
"node-abi": ["node-abi@3.78.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ=="],
|
||||
|
||||
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||
|
||||
"node-forge": ["node-forge@1.3.1", "", {}, "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="],
|
||||
@@ -1356,8 +1322,6 @@
|
||||
|
||||
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="],
|
||||
|
||||
"oniguruma-to-es": ["oniguruma-to-es@4.3.3", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg=="],
|
||||
@@ -1394,8 +1358,6 @@
|
||||
|
||||
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||
|
||||
"prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
|
||||
|
||||
"prettier": ["prettier@2.8.7", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw=="],
|
||||
|
||||
"pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
|
||||
@@ -1408,8 +1370,6 @@
|
||||
|
||||
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||
|
||||
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="],
|
||||
@@ -1426,8 +1386,6 @@
|
||||
|
||||
"raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="],
|
||||
|
||||
"rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
|
||||
|
||||
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
|
||||
|
||||
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
|
||||
@@ -1436,7 +1394,7 @@
|
||||
|
||||
"react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||
"react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
|
||||
|
||||
"react-remove-scroll": ["react-remove-scroll@2.7.0", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-sGsQtcjMqdQyijAHytfGEELB8FufGbfXIsvUTe+NLx1GDRJCXtCFLBLUI1eyZCKXXvbEU2C6gai0PZKoIE9Vbg=="],
|
||||
|
||||
@@ -1444,8 +1402,6 @@
|
||||
|
||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||
|
||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="],
|
||||
@@ -1538,7 +1494,7 @@
|
||||
|
||||
"sharp": ["sharp@0.34.3", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3", "@img/sharp-darwin-x64": "0.34.3", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", "@img/sharp-libvips-linux-arm64": "1.2.0", "@img/sharp-libvips-linux-ppc64": "1.2.0", "@img/sharp-libvips-linux-s390x": "1.2.0", "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", "@img/sharp-linux-arm": "0.34.3", "@img/sharp-linux-arm64": "0.34.3", "@img/sharp-linux-ppc64": "0.34.3", "@img/sharp-linux-s390x": "0.34.3", "@img/sharp-linux-x64": "0.34.3", "@img/sharp-linuxmusl-arm64": "0.34.3", "@img/sharp-linuxmusl-x64": "0.34.3", "@img/sharp-wasm32": "0.34.3", "@img/sharp-win32-arm64": "0.34.3", "@img/sharp-win32-ia32": "0.34.3", "@img/sharp-win32-x64": "0.34.3" } }, "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg=="],
|
||||
|
||||
"shiki": ["shiki@3.12.2", "", { "dependencies": { "@shikijs/core": "3.12.2", "@shikijs/engine-javascript": "3.12.2", "@shikijs/engine-oniguruma": "3.12.2", "@shikijs/langs": "3.12.2", "@shikijs/themes": "3.12.2", "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-uIrKI+f9IPz1zDT+GMz+0RjzKJiijVr6WDWm9Pe3NNY6QigKCfifCEv9v9R2mDASKKjzjQ2QpFLcxaR3iHSnMA=="],
|
||||
"shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="],
|
||||
|
||||
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||
|
||||
@@ -1550,10 +1506,6 @@
|
||||
|
||||
"siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
|
||||
|
||||
"simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="],
|
||||
|
||||
"simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="],
|
||||
|
||||
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
|
||||
|
||||
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
|
||||
@@ -1576,16 +1528,12 @@
|
||||
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
||||
|
||||
"stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="],
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
|
||||
|
||||
"strip-literal": ["strip-literal@3.0.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA=="],
|
||||
|
||||
"strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
|
||||
@@ -1600,14 +1548,10 @@
|
||||
|
||||
"tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.15", "", {}, "sha512-k2WLnWkYFkdpRv+Oby3EBXIyQC8/s1HOFMBUViwtAh6Z5uAozeUSMQlIsn/c6Q2iJzqG6aJT3wdPaRNj70iYxQ=="],
|
||||
"tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="],
|
||||
|
||||
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
||||
|
||||
"tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="],
|
||||
|
||||
"tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
|
||||
|
||||
"tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
|
||||
|
||||
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
||||
@@ -1644,8 +1588,6 @@
|
||||
|
||||
"tsx": ["tsx@4.20.6", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg=="],
|
||||
|
||||
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
|
||||
|
||||
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
|
||||
|
||||
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
||||
@@ -1708,8 +1650,6 @@
|
||||
|
||||
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
||||
|
||||
"uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="],
|
||||
@@ -1724,7 +1664,7 @@
|
||||
|
||||
"vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="],
|
||||
|
||||
"vite": ["vite@6.3.6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA=="],
|
||||
"vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
|
||||
|
||||
"vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
|
||||
|
||||
@@ -1786,8 +1726,6 @@
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"ws": ["ws@8.18.2", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ=="],
|
||||
|
||||
"xml": ["xml@1.0.1", "", {}, "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw=="],
|
||||
@@ -1834,8 +1772,6 @@
|
||||
|
||||
"@ampproject/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
|
||||
|
||||
"@astrojs/telemetry/ci-info": ["ci-info@4.2.0", "", {}, "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg=="],
|
||||
@@ -1860,19 +1796,31 @@
|
||||
|
||||
"@babel/template/@babel/types": ["@babel/types@7.27.3", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw=="],
|
||||
|
||||
"@octokit/core/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-avatar/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="],
|
||||
|
||||
"@octokit/endpoint/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-avatar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@octokit/graphql/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@octokit/request/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@octokit/request-error/@octokit/types": ["@octokit/types@14.1.0", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
|
||||
"@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-progress/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="],
|
||||
|
||||
"@radix-ui/react-progress/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
@@ -1882,7 +1830,7 @@
|
||||
|
||||
"@tailwindcss/node/lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
|
||||
|
||||
"@tailwindcss/node/magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="],
|
||||
"@tailwindcss/node/magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="],
|
||||
|
||||
@@ -1912,6 +1860,8 @@
|
||||
|
||||
"@types/babel__traverse/@babel/types": ["@babel/types@7.27.3", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw=="],
|
||||
|
||||
"@types/bcryptjs/bcryptjs": ["bcryptjs@3.0.2", "", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog=="],
|
||||
|
||||
"accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
@@ -1926,8 +1876,6 @@
|
||||
|
||||
"basic-auth/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
||||
|
||||
"body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
|
||||
@@ -2016,22 +1964,12 @@
|
||||
|
||||
"yaml-language-server/yaml": ["yaml@2.2.2", "", {}, "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="],
|
||||
|
||||
"@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||
|
||||
"@babel/helper-module-imports/@babel/traverse/@babel/generator": ["@babel/generator@7.27.3", "", { "dependencies": { "@babel/parser": "^7.27.3", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q=="],
|
||||
|
||||
"@babel/helper-module-imports/@babel/traverse/@babel/parser": ["@babel/parser@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw=="],
|
||||
@@ -2040,20 +1978,6 @@
|
||||
|
||||
"@babel/helper-module-transforms/@babel/traverse/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
|
||||
"@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@octokit/graphql/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@25.1.0", "", {}, "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA=="],
|
||||
|
||||
"@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
|
||||
|
||||
"@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
|
||||
@@ -2094,6 +2018,8 @@
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="],
|
||||
|
||||
"cmdk/@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"express/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="],
|
||||
@@ -2116,6 +2042,8 @@
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="],
|
||||
|
||||
"vaul/@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"widest-line/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
|
||||
"widest-line/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
@@ -1,483 +0,0 @@
|
||||
# Nix Deployment Guide
|
||||
|
||||
This guide covers deploying Gitea Mirror using Nix flakes. The Nix deployment follows the same minimal configuration philosophy as `docker-compose.alt.yml` - secrets are auto-generated, and everything else can be configured via the web UI.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Nix 2.4+ installed
|
||||
- For NixOS module: NixOS 23.05+
|
||||
|
||||
### Enable Flakes (Recommended)
|
||||
|
||||
To enable flakes permanently and avoid typing flags, add to `/etc/nix/nix.conf` or `~/.config/nix/nix.conf`:
|
||||
```
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
|
||||
**Note:** If you don't enable flakes globally, add `--extra-experimental-features 'nix-command flakes'` to all nix commands shown below.
|
||||
|
||||
## Quick Start (Zero Configuration!)
|
||||
|
||||
### Run Immediately - No Setup Required
|
||||
|
||||
```bash
|
||||
# Run directly from the flake (local)
|
||||
nix run --extra-experimental-features 'nix-command flakes' .#gitea-mirror
|
||||
|
||||
# Or from GitHub (once published)
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# If you have flakes enabled globally, simply:
|
||||
nix run .#gitea-mirror
|
||||
```
|
||||
|
||||
That's it! On first run:
|
||||
- Secrets (`BETTER_AUTH_SECRET` and `ENCRYPTION_SECRET`) are auto-generated
|
||||
- Database is automatically created and initialized
|
||||
- Startup recovery and repair scripts run automatically
|
||||
- Access the web UI at http://localhost:4321
|
||||
|
||||
Everything else (GitHub credentials, Gitea settings, mirror options) is configured through the web interface after signup.
|
||||
|
||||
### Development Environment
|
||||
|
||||
```bash
|
||||
# Enter development shell with all dependencies
|
||||
nix develop --extra-experimental-features 'nix-command flakes'
|
||||
|
||||
# Or use direnv for automatic environment loading (handles flags automatically)
|
||||
echo "use flake" > .envrc
|
||||
direnv allow
|
||||
```
|
||||
|
||||
### Build and Install
|
||||
|
||||
```bash
|
||||
# Build the package
|
||||
nix build --extra-experimental-features 'nix-command flakes'
|
||||
|
||||
# Run the built package
|
||||
./result/bin/gitea-mirror
|
||||
|
||||
# Install to your profile
|
||||
nix profile install --extra-experimental-features 'nix-command flakes' .#gitea-mirror
|
||||
```
|
||||
|
||||
## What Happens on First Run?
|
||||
|
||||
Following the same pattern as the Docker deployment, the Nix package automatically:
|
||||
|
||||
1. **Creates data directory**: `~/.local/share/gitea-mirror` (or `$DATA_DIR`)
|
||||
2. **Generates secrets** (stored securely in data directory):
|
||||
- `BETTER_AUTH_SECRET` - Session authentication (32-char hex)
|
||||
- `ENCRYPTION_SECRET` - Token encryption (48-char base64)
|
||||
3. **Initializes database**: SQLite database with Drizzle migrations
|
||||
4. **Runs startup scripts**:
|
||||
- Environment configuration loader
|
||||
- Crash recovery for interrupted jobs
|
||||
- Repository status repair
|
||||
5. **Starts the application** with graceful shutdown handling
|
||||
|
||||
## NixOS Module - Minimal Deployment
|
||||
|
||||
### Simplest Possible Configuration
|
||||
|
||||
Add to your NixOS configuration (`/etc/nixos/configuration.nix`):
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
gitea-mirror.url = "github:RayLabsHQ/gitea-mirror";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, gitea-mirror, ... }: {
|
||||
nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
gitea-mirror.nixosModules.default
|
||||
{
|
||||
# That's it! Just enable the service
|
||||
services.gitea-mirror.enable = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Apply with:
|
||||
```bash
|
||||
sudo nixos-rebuild switch
|
||||
```
|
||||
|
||||
Access at http://localhost:4321, sign up (first user is admin), and configure everything via the web UI.
|
||||
|
||||
### Production Configuration
|
||||
|
||||
For production with custom domain and firewall:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
host = "0.0.0.0";
|
||||
port = 4321;
|
||||
betterAuthUrl = "https://mirror.example.com";
|
||||
betterAuthTrustedOrigins = "https://mirror.example.com";
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
# Optional: Use with nginx reverse proxy
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."mirror.example.com" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:4321";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced: Manual Secret Management
|
||||
|
||||
If you prefer to manage secrets manually (e.g., with sops-nix or agenix):
|
||||
|
||||
1. Create a secrets file:
|
||||
```bash
|
||||
# /var/lib/gitea-mirror/secrets.env
|
||||
BETTER_AUTH_SECRET=your-32-character-minimum-secret-key-here
|
||||
ENCRYPTION_SECRET=your-encryption-secret-here
|
||||
```
|
||||
|
||||
2. Reference it in your configuration:
|
||||
```nix
|
||||
{
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
environmentFile = "/var/lib/gitea-mirror/secrets.env";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Full Configuration Options
|
||||
|
||||
```nix
|
||||
{
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
package = gitea-mirror.packages.x86_64-linux.default; # Override package
|
||||
dataDir = "/var/lib/gitea-mirror";
|
||||
user = "gitea-mirror";
|
||||
group = "gitea-mirror";
|
||||
host = "0.0.0.0";
|
||||
port = 4321;
|
||||
betterAuthUrl = "https://mirror.example.com";
|
||||
betterAuthTrustedOrigins = "https://mirror.example.com";
|
||||
|
||||
# Concurrency controls (match docker-compose.alt.yml)
|
||||
mirrorIssueConcurrency = 3; # Set to 1 for perfect chronological order
|
||||
mirrorPullRequestConcurrency = 5; # Set to 1 for perfect chronological order
|
||||
|
||||
environmentFile = null; # Optional secrets file
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Service Management (NixOS)
|
||||
|
||||
```bash
|
||||
# Start the service
|
||||
sudo systemctl start gitea-mirror
|
||||
|
||||
# Stop the service
|
||||
sudo systemctl stop gitea-mirror
|
||||
|
||||
# Restart the service
|
||||
sudo systemctl restart gitea-mirror
|
||||
|
||||
# Check status
|
||||
sudo systemctl status gitea-mirror
|
||||
|
||||
# View logs
|
||||
sudo journalctl -u gitea-mirror -f
|
||||
|
||||
# Health check
|
||||
curl http://localhost:4321/api/health
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All variables from `docker-compose.alt.yml` are supported:
|
||||
|
||||
```bash
|
||||
# === AUTO-GENERATED (Don't set unless you want specific values) ===
|
||||
BETTER_AUTH_SECRET # Auto-generated, stored in data dir
|
||||
ENCRYPTION_SECRET # Auto-generated, stored in data dir
|
||||
|
||||
# === CORE SETTINGS (Have good defaults) ===
|
||||
DATA_DIR="$HOME/.local/share/gitea-mirror"
|
||||
DATABASE_URL="file:$DATA_DIR/gitea-mirror.db"
|
||||
HOST="0.0.0.0"
|
||||
PORT="4321"
|
||||
NODE_ENV="production"
|
||||
|
||||
# === BETTER AUTH (Override for custom domains) ===
|
||||
BETTER_AUTH_URL="http://localhost:4321"
|
||||
BETTER_AUTH_TRUSTED_ORIGINS="http://localhost:4321"
|
||||
PUBLIC_BETTER_AUTH_URL="http://localhost:4321"
|
||||
|
||||
# === CONCURRENCY CONTROLS ===
|
||||
MIRROR_ISSUE_CONCURRENCY=3 # Default: 3 (set to 1 for perfect order)
|
||||
MIRROR_PULL_REQUEST_CONCURRENCY=5 # Default: 5 (set to 1 for perfect order)
|
||||
|
||||
# === CONFIGURE VIA WEB UI (Not needed at startup) ===
|
||||
# GitHub credentials, Gitea settings, mirror options, scheduling, etc.
|
||||
# All configured after signup through the web interface
|
||||
```
|
||||
|
||||
## Database Management
|
||||
|
||||
The Nix package includes a database management helper:
|
||||
|
||||
```bash
|
||||
# Initialize database (done automatically on first run)
|
||||
gitea-mirror-db init
|
||||
|
||||
# Check database health
|
||||
gitea-mirror-db check
|
||||
|
||||
# Fix database issues
|
||||
gitea-mirror-db fix
|
||||
|
||||
# Reset users
|
||||
gitea-mirror-db reset-users
|
||||
```
|
||||
|
||||
## Home Manager Integration
|
||||
|
||||
For single-user deployments:
|
||||
|
||||
```nix
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
gitea-mirror = (import (fetchTarball "https://github.com/RayLabsHQ/gitea-mirror/archive/main.tar.gz")).packages.${pkgs.system}.default;
|
||||
in {
|
||||
home.packages = [ gitea-mirror ];
|
||||
|
||||
# Optional: Run as user service
|
||||
systemd.user.services.gitea-mirror = {
|
||||
Unit = {
|
||||
Description = "Gitea Mirror Service";
|
||||
After = [ "network.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${gitea-mirror}/bin/gitea-mirror";
|
||||
Restart = "always";
|
||||
Environment = [
|
||||
"DATA_DIR=%h/.local/share/gitea-mirror"
|
||||
"HOST=127.0.0.1"
|
||||
"PORT=4321"
|
||||
];
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Docker Image from Nix (Optional)
|
||||
|
||||
You can also use Nix to create a Docker image:
|
||||
|
||||
```nix
|
||||
# Add to flake.nix packages section
|
||||
dockerImage = pkgs.dockerTools.buildLayeredImage {
|
||||
name = "gitea-mirror";
|
||||
tag = "latest";
|
||||
contents = [ self.packages.${system}.default pkgs.cacert pkgs.openssl ];
|
||||
config = {
|
||||
Cmd = [ "${self.packages.${system}.default}/bin/gitea-mirror" ];
|
||||
ExposedPorts = { "4321/tcp" = {}; };
|
||||
Env = [
|
||||
"DATA_DIR=/data"
|
||||
"DATABASE_URL=file:/data/gitea-mirror.db"
|
||||
];
|
||||
Volumes = { "/data" = {}; };
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Build and load:
|
||||
```bash
|
||||
nix build --extra-experimental-features 'nix-command flakes' .#dockerImage
|
||||
docker load < result
|
||||
docker run -p 4321:4321 -v gitea-mirror-data:/data gitea-mirror:latest
|
||||
```
|
||||
|
||||
## Comparison: Docker vs Nix
|
||||
|
||||
Both deployment methods follow the same philosophy:
|
||||
|
||||
| Feature | Docker Compose | Nix |
|
||||
|---------|---------------|-----|
|
||||
| **Configuration** | Minimal (only BETTER_AUTH_SECRET) | Zero config (auto-generated) |
|
||||
| **Secret Generation** | Auto-generated & persisted | Auto-generated & persisted |
|
||||
| **Database Init** | Automatic on first run | Automatic on first run |
|
||||
| **Startup Scripts** | Runs recovery/repair/env-config | Runs recovery/repair/env-config |
|
||||
| **Graceful Shutdown** | Signal handling in entrypoint | Signal handling in wrapper |
|
||||
| **Health Check** | Docker healthcheck | systemd timer (optional) |
|
||||
| **Updates** | `docker pull` | `nix flake update && nixos-rebuild` |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check Auto-Generated Secrets
|
||||
```bash
|
||||
# For standalone
|
||||
cat ~/.local/share/gitea-mirror/.better_auth_secret
|
||||
cat ~/.local/share/gitea-mirror/.encryption_secret
|
||||
|
||||
# For NixOS service
|
||||
sudo cat /var/lib/gitea-mirror/.better_auth_secret
|
||||
sudo cat /var/lib/gitea-mirror/.encryption_secret
|
||||
```
|
||||
|
||||
### Database Issues
|
||||
```bash
|
||||
# Check if database exists
|
||||
ls -la ~/.local/share/gitea-mirror/gitea-mirror.db
|
||||
|
||||
# Reinitialize (deletes all data!)
|
||||
rm ~/.local/share/gitea-mirror/gitea-mirror.db
|
||||
gitea-mirror-db init
|
||||
```
|
||||
|
||||
### Permission Issues (NixOS)
|
||||
```bash
|
||||
sudo chown -R gitea-mirror:gitea-mirror /var/lib/gitea-mirror
|
||||
sudo chmod 700 /var/lib/gitea-mirror
|
||||
```
|
||||
|
||||
### Port Already in Use
|
||||
```bash
|
||||
# Change port
|
||||
export PORT=8080
|
||||
gitea-mirror
|
||||
|
||||
# Or in NixOS config
|
||||
services.gitea-mirror.port = 8080;
|
||||
```
|
||||
|
||||
### View Startup Logs
|
||||
```bash
|
||||
# Standalone (verbose output on console)
|
||||
gitea-mirror
|
||||
|
||||
# NixOS service
|
||||
sudo journalctl -u gitea-mirror -f --since "5 minutes ago"
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
### Standalone Installation
|
||||
```bash
|
||||
# Update flake lock
|
||||
nix flake update --extra-experimental-features 'nix-command flakes'
|
||||
|
||||
# Rebuild
|
||||
nix build --extra-experimental-features 'nix-command flakes'
|
||||
|
||||
# Or update profile
|
||||
nix profile upgrade --extra-experimental-features 'nix-command flakes' gitea-mirror
|
||||
```
|
||||
|
||||
### NixOS
|
||||
```bash
|
||||
# Update input
|
||||
sudo nix flake lock --update-input gitea-mirror --extra-experimental-features 'nix-command flakes'
|
||||
|
||||
# Rebuild system
|
||||
sudo nixos-rebuild switch --flake .#your-hostname
|
||||
```
|
||||
|
||||
## Migration from Docker
|
||||
|
||||
To migrate from Docker to Nix while keeping your data:
|
||||
|
||||
1. **Stop Docker container:**
|
||||
```bash
|
||||
docker-compose -f docker-compose.alt.yml down
|
||||
```
|
||||
|
||||
2. **Copy data directory:**
|
||||
```bash
|
||||
# For standalone
|
||||
cp -r ./data ~/.local/share/gitea-mirror
|
||||
|
||||
# For NixOS
|
||||
sudo cp -r ./data /var/lib/gitea-mirror
|
||||
sudo chown -R gitea-mirror:gitea-mirror /var/lib/gitea-mirror
|
||||
```
|
||||
|
||||
3. **Copy secrets (if you want to keep them):**
|
||||
```bash
|
||||
# Extract from Docker volume
|
||||
docker run --rm -v gitea-mirror_data:/data alpine \
|
||||
cat /data/.better_auth_secret > better_auth_secret
|
||||
docker run --rm -v gitea-mirror_data:/data alpine \
|
||||
cat /data/.encryption_secret > encryption_secret
|
||||
|
||||
# Copy to new location
|
||||
cp better_auth_secret ~/.local/share/gitea-mirror/.better_auth_secret
|
||||
cp encryption_secret ~/.local/share/gitea-mirror/.encryption_secret
|
||||
chmod 600 ~/.local/share/gitea-mirror/.*_secret
|
||||
```
|
||||
|
||||
4. **Start Nix version:**
|
||||
```bash
|
||||
gitea-mirror
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
Example GitHub Actions workflow:
|
||||
|
||||
```yaml
|
||||
name: Build with Nix
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v24
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: gitea-mirror
|
||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- run: nix build
|
||||
- run: nix flake check
|
||||
# Note: GitHub Actions runner usually has flakes enabled by install-nix-action
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [Nix Manual](https://nixos.org/manual/nix/stable/)
|
||||
- [NixOS Options Search](https://search.nixos.org/options)
|
||||
- [Nix Pills Tutorial](https://nixos.org/guides/nix-pills/)
|
||||
- [Project Documentation](../README.md)
|
||||
- [Docker Deployment](../docker-compose.alt.yml) - Equivalent minimal config
|
||||
@@ -1,352 +0,0 @@
|
||||
# Nix Package Distribution Guide
|
||||
|
||||
This guide explains how Gitea Mirror is distributed via Nix and how users can consume it.
|
||||
|
||||
## Distribution Methods
|
||||
|
||||
### Method 1: Direct GitHub Usage (Zero Infrastructure)
|
||||
|
||||
**No CI, releases, or setup needed!** Users can consume directly from GitHub:
|
||||
|
||||
```bash
|
||||
# Latest from main branch
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Pin to specific commit
|
||||
nix run github:RayLabsHQ/gitea-mirror/abc123def
|
||||
|
||||
# Pin to git tag
|
||||
nix run github:RayLabsHQ/gitea-mirror/v3.8.11
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
1. Nix fetches the repository from GitHub
|
||||
2. Nix reads `flake.nix` and `flake.lock`
|
||||
3. Nix builds the package locally on the user's machine
|
||||
4. Package is cached in `/nix/store` for reuse
|
||||
|
||||
**Pros:**
|
||||
- Zero infrastructure needed
|
||||
- Works immediately after pushing code
|
||||
- Users always get reproducible builds
|
||||
|
||||
**Cons:**
|
||||
- Users must build from source (slower first time)
|
||||
- Requires build dependencies (Bun, etc.)
|
||||
|
||||
---
|
||||
|
||||
### Method 2: Binary Cache (Recommended)
|
||||
|
||||
Pre-build packages and cache them so users download binaries instead of building:
|
||||
|
||||
#### Setup: Cachix (Free for Public Projects)
|
||||
|
||||
1. **Create account:** https://cachix.org/
|
||||
2. **Create cache:** `gitea-mirror` (public)
|
||||
3. **Add secret to GitHub:** `Settings → Secrets → CACHIX_AUTH_TOKEN`
|
||||
4. **GitHub Actions builds automatically** (see `.github/workflows/nix-build.yml`)
|
||||
|
||||
#### User Experience:
|
||||
|
||||
```bash
|
||||
# First time: Configure cache
|
||||
cachix use gitea-mirror
|
||||
|
||||
# Or add to nix.conf:
|
||||
# substituters = https://cache.nixos.org https://gitea-mirror.cachix.org
|
||||
# trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= gitea-mirror.cachix.org-1:YOUR_KEY_HERE
|
||||
|
||||
# Then use normally - downloads pre-built binaries!
|
||||
nix run github:RayLabsHQ/gitea-mirror
|
||||
```
|
||||
|
||||
**Pros:**
|
||||
- Fast installation (no compilation)
|
||||
- Reduced bandwidth/CPU for users
|
||||
- Professional experience
|
||||
|
||||
**Cons:**
|
||||
- Requires Cachix account (free for public)
|
||||
- Requires CI setup
|
||||
|
||||
---
|
||||
|
||||
### Method 3: nixpkgs Submission (Official Distribution)
|
||||
|
||||
Submit to the official Nix package repository for maximum visibility.
|
||||
|
||||
#### Process:
|
||||
|
||||
1. **Prepare package** (already done with `flake.nix`)
|
||||
2. **Test thoroughly**
|
||||
3. **Submit PR to nixpkgs:** https://github.com/NixOS/nixpkgs
|
||||
|
||||
#### User Experience:
|
||||
|
||||
```bash
|
||||
# After acceptance into nixpkgs
|
||||
nix run nixpkgs#gitea-mirror
|
||||
|
||||
# NixOS configuration
|
||||
environment.systemPackages = [ pkgs.gitea-mirror ];
|
||||
```
|
||||
|
||||
**Pros:**
|
||||
- Maximum discoverability (official repo)
|
||||
- Trusted by Nix community
|
||||
- Included in NixOS search
|
||||
- Binary caching by cache.nixos.org
|
||||
|
||||
**Cons:**
|
||||
- Submission/review process
|
||||
- Must follow nixpkgs guidelines
|
||||
- Updates require PRs
|
||||
|
||||
---
|
||||
|
||||
## Current Distribution Strategy
|
||||
|
||||
### Phase 1: Direct GitHub (Immediate) ✅
|
||||
|
||||
Already working! Users can:
|
||||
|
||||
```bash
|
||||
nix run github:RayLabsHQ/gitea-mirror
|
||||
```
|
||||
|
||||
### Phase 2: Binary Cache (Recommended Next)
|
||||
|
||||
Set up Cachix for faster installs:
|
||||
|
||||
1. Create Cachix cache
|
||||
2. Add `CACHIX_AUTH_TOKEN` secret to GitHub
|
||||
3. Workflow already created in `.github/workflows/nix-build.yml`
|
||||
4. Add instructions to docs
|
||||
|
||||
### Phase 3: Version Releases (Optional)
|
||||
|
||||
Tag releases for version pinning:
|
||||
|
||||
```bash
|
||||
git tag v3.8.11
|
||||
git push origin v3.8.11
|
||||
|
||||
# Users can then pin:
|
||||
nix run github:RayLabsHQ/gitea-mirror/v3.8.11
|
||||
```
|
||||
|
||||
### Phase 4: nixpkgs Submission (Long Term)
|
||||
|
||||
Once package is stable and well-tested, submit to nixpkgs.
|
||||
|
||||
---
|
||||
|
||||
## User Documentation
|
||||
|
||||
### For Users: How to Install
|
||||
|
||||
Add this to your `docs/NIX_DEPLOYMENT.md`:
|
||||
|
||||
#### Option 1: Direct Install (No Configuration)
|
||||
|
||||
```bash
|
||||
# Run immediately
|
||||
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
|
||||
# Install to profile
|
||||
nix profile install --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror
|
||||
```
|
||||
|
||||
#### Option 2: With Binary Cache (Faster)
|
||||
|
||||
```bash
|
||||
# One-time setup
|
||||
cachix use gitea-mirror
|
||||
|
||||
# Then install (downloads pre-built binary)
|
||||
nix profile install github:RayLabsHQ/gitea-mirror
|
||||
```
|
||||
|
||||
#### Option 3: Pin to Specific Version
|
||||
|
||||
```bash
|
||||
# Pin to git tag
|
||||
nix run github:RayLabsHQ/gitea-mirror/v3.8.11
|
||||
|
||||
# Pin to commit
|
||||
nix run github:RayLabsHQ/gitea-mirror/abc123def
|
||||
|
||||
# Lock in flake.nix
|
||||
inputs.gitea-mirror.url = "github:RayLabsHQ/gitea-mirror/v3.8.11";
|
||||
```
|
||||
|
||||
#### Option 4: NixOS Configuration
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
gitea-mirror.url = "github:RayLabsHQ/gitea-mirror";
|
||||
# Or pin to version:
|
||||
# gitea-mirror.url = "github:RayLabsHQ/gitea-mirror/v3.8.11";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, gitea-mirror, ... }: {
|
||||
nixosConfigurations.your-host = nixpkgs.lib.nixosSystem {
|
||||
modules = [
|
||||
gitea-mirror.nixosModules.default
|
||||
{
|
||||
services.gitea-mirror = {
|
||||
enable = true;
|
||||
betterAuthUrl = "https://mirror.example.com";
|
||||
openFirewall = true;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintaining the Distribution
|
||||
|
||||
### Releasing New Versions
|
||||
|
||||
```bash
|
||||
# 1. Update version in package.json
|
||||
vim package.json # Update version field
|
||||
|
||||
# 2. Update flake.nix version (line 17)
|
||||
vim flake.nix # Update version = "X.Y.Z";
|
||||
|
||||
# 3. Commit changes
|
||||
git add package.json flake.nix
|
||||
git commit -m "chore: bump version to vX.Y.Z"
|
||||
|
||||
# 4. Create git tag
|
||||
git tag vX.Y.Z
|
||||
git push origin main
|
||||
git push origin vX.Y.Z
|
||||
|
||||
# 5. GitHub Actions builds and caches automatically
|
||||
```
|
||||
|
||||
Users can then pin to the new version:
|
||||
```bash
|
||||
nix run github:RayLabsHQ/gitea-mirror/vX.Y.Z
|
||||
```
|
||||
|
||||
### Updating Flake Lock
|
||||
|
||||
The `flake.lock` file pins all dependencies. Update it periodically:
|
||||
|
||||
```bash
|
||||
# Update all inputs
|
||||
nix flake update
|
||||
|
||||
# Update specific input
|
||||
nix flake lock --update-input nixpkgs
|
||||
|
||||
# Test after update
|
||||
nix build
|
||||
nix flake check
|
||||
|
||||
# Commit the updated lock file
|
||||
git add flake.lock
|
||||
git commit -m "chore: update flake dependencies"
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Distribution Issues
|
||||
|
||||
### Users Report Build Failures
|
||||
|
||||
1. **Check GitHub Actions:** Ensure CI is passing
|
||||
2. **Test locally:** `nix flake check`
|
||||
3. **Check flake.lock:** May need update if dependencies changed
|
||||
|
||||
### Cachix Not Working
|
||||
|
||||
1. **Verify cache exists:** https://gitea-mirror.cachix.org
|
||||
2. **Check GitHub secret:** `CACHIX_AUTH_TOKEN` is set
|
||||
3. **Review workflow logs:** Ensure build + push succeeded
|
||||
|
||||
### Version Pinning Not Working
|
||||
|
||||
```bash
|
||||
# Verify tag exists
|
||||
git tag -l
|
||||
|
||||
# Ensure tag is pushed
|
||||
git ls-remote --tags origin
|
||||
|
||||
# Test specific tag
|
||||
nix run github:RayLabsHQ/gitea-mirror/v3.8.11
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced: Custom Binary Cache
|
||||
|
||||
If you prefer self-hosting instead of Cachix:
|
||||
|
||||
### Option 1: S3-Compatible Storage
|
||||
|
||||
```nix
|
||||
# Generate signing key
|
||||
nix-store --generate-binary-cache-key cache.example.com cache-priv-key.pem cache-pub-key.pem
|
||||
|
||||
# Push to S3
|
||||
nix copy --to s3://my-nix-cache?region=us-east-1 $(nix-build)
|
||||
```
|
||||
|
||||
Users configure:
|
||||
```nix
|
||||
substituters = https://my-bucket.s3.amazonaws.com/nix-cache
|
||||
trusted-public-keys = cache.example.com:BASE64_PUBLIC_KEY
|
||||
```
|
||||
|
||||
### Option 2: Self-Hosted Nix Store
|
||||
|
||||
Run `nix-serve` on your server:
|
||||
|
||||
```bash
|
||||
# On server
|
||||
nix-serve -p 8080
|
||||
|
||||
# Behind nginx/caddy
|
||||
proxy_pass http://localhost:8080;
|
||||
```
|
||||
|
||||
Users configure:
|
||||
```nix
|
||||
substituters = https://cache.example.com
|
||||
trusted-public-keys = YOUR_KEY
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Distribution Methods
|
||||
|
||||
| Method | Setup Time | User Speed | Cost | Discoverability |
|
||||
|--------|-----------|------------|------|-----------------|
|
||||
| Direct GitHub | 0 min | Slow (build) | Free | Low |
|
||||
| Cachix | 5 min | Fast (binary) | Free (public) | Medium |
|
||||
| nixpkgs | Hours/days | Fast (binary) | Free | High |
|
||||
| Self-hosted | 30+ min | Fast (binary) | Server cost | Low |
|
||||
|
||||
**Recommendation:** Start with **Direct GitHub** (works now), add **Cachix** for better UX (5 min), consider **nixpkgs** later for maximum reach.
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Nix Flakes Documentation](https://nixos.wiki/wiki/Flakes)
|
||||
- [Cachix Documentation](https://docs.cachix.org/)
|
||||
- [nixpkgs Contributing Guide](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md)
|
||||
- [Nix Binary Cache Setup](https://nixos.org/manual/nix/stable/package-management/binary-cache-substituter.html)
|
||||
61
flake.lock
generated
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1761672384,
|
||||
"narHash": "sha256-o9KF3DJL7g7iYMZq9SWgfS1BFlNbsm6xplRjVlOCkXI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "08dacfca559e1d7da38f3cf05f1f45ee9bfd213c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
395
flake.nix
@@ -1,395 +0,0 @@
|
||||
{
|
||||
description = "Gitea Mirror - Self-hosted GitHub to Gitea mirroring service";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
# Build the application
|
||||
gitea-mirror = pkgs.stdenv.mkDerivation {
|
||||
pname = "gitea-mirror";
|
||||
version = "3.8.11";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
bun
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
sqlite
|
||||
openssl
|
||||
];
|
||||
|
||||
configurePhase = ''
|
||||
export HOME=$TMPDIR
|
||||
export BUN_INSTALL=$TMPDIR/.bun
|
||||
export PATH=$BUN_INSTALL/bin:$PATH
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
# Install dependencies
|
||||
bun install --frozen-lockfile --no-progress
|
||||
|
||||
# Build the application
|
||||
bun run build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/lib/gitea-mirror
|
||||
mkdir -p $out/bin
|
||||
|
||||
# Copy the built application
|
||||
cp -r dist $out/lib/gitea-mirror/
|
||||
cp -r node_modules $out/lib/gitea-mirror/
|
||||
cp -r scripts $out/lib/gitea-mirror/
|
||||
cp package.json $out/lib/gitea-mirror/
|
||||
|
||||
# Create entrypoint script that matches Docker behavior
|
||||
cat > $out/bin/gitea-mirror <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# === DEFAULT CONFIGURATION ===
|
||||
# These match docker-compose.alt.yml defaults
|
||||
export DATA_DIR=''${DATA_DIR:-"$HOME/.local/share/gitea-mirror"}
|
||||
export DATABASE_URL=''${DATABASE_URL:-"file:$DATA_DIR/gitea-mirror.db"}
|
||||
export HOST=''${HOST:-"0.0.0.0"}
|
||||
export PORT=''${PORT:-"4321"}
|
||||
export NODE_ENV=''${NODE_ENV:-"production"}
|
||||
|
||||
# Better Auth configuration
|
||||
export BETTER_AUTH_URL=''${BETTER_AUTH_URL:-"http://localhost:4321"}
|
||||
export BETTER_AUTH_TRUSTED_ORIGINS=''${BETTER_AUTH_TRUSTED_ORIGINS:-"http://localhost:4321"}
|
||||
export PUBLIC_BETTER_AUTH_URL=''${PUBLIC_BETTER_AUTH_URL:-"http://localhost:4321"}
|
||||
|
||||
# Concurrency settings (match docker-compose.alt.yml)
|
||||
export MIRROR_ISSUE_CONCURRENCY=''${MIRROR_ISSUE_CONCURRENCY:-3}
|
||||
export MIRROR_PULL_REQUEST_CONCURRENCY=''${MIRROR_PULL_REQUEST_CONCURRENCY:-5}
|
||||
|
||||
# Create data directory
|
||||
mkdir -p "$DATA_DIR"
|
||||
cd $out/lib/gitea-mirror
|
||||
|
||||
# === AUTO-GENERATE SECRETS ===
|
||||
BETTER_AUTH_SECRET_FILE="$DATA_DIR/.better_auth_secret"
|
||||
ENCRYPTION_SECRET_FILE="$DATA_DIR/.encryption_secret"
|
||||
|
||||
# Generate BETTER_AUTH_SECRET if not provided
|
||||
if [ -z "$BETTER_AUTH_SECRET" ]; then
|
||||
if [ -f "$BETTER_AUTH_SECRET_FILE" ]; then
|
||||
echo "Using previously generated BETTER_AUTH_SECRET"
|
||||
export BETTER_AUTH_SECRET=$(cat "$BETTER_AUTH_SECRET_FILE")
|
||||
else
|
||||
echo "Generating a secure random BETTER_AUTH_SECRET"
|
||||
GENERATED_SECRET=$(${pkgs.openssl}/bin/openssl rand -hex 32)
|
||||
export BETTER_AUTH_SECRET="$GENERATED_SECRET"
|
||||
echo "$GENERATED_SECRET" > "$BETTER_AUTH_SECRET_FILE"
|
||||
chmod 600 "$BETTER_AUTH_SECRET_FILE"
|
||||
echo "✅ BETTER_AUTH_SECRET generated and saved to $BETTER_AUTH_SECRET_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate ENCRYPTION_SECRET if not provided
|
||||
if [ -z "$ENCRYPTION_SECRET" ]; then
|
||||
if [ -f "$ENCRYPTION_SECRET_FILE" ]; then
|
||||
echo "Using previously generated ENCRYPTION_SECRET"
|
||||
export ENCRYPTION_SECRET=$(cat "$ENCRYPTION_SECRET_FILE")
|
||||
else
|
||||
echo "Generating a secure random ENCRYPTION_SECRET"
|
||||
GENERATED_ENCRYPTION_SECRET=$(${pkgs.openssl}/bin/openssl rand -base64 36)
|
||||
export ENCRYPTION_SECRET="$GENERATED_ENCRYPTION_SECRET"
|
||||
echo "$GENERATED_ENCRYPTION_SECRET" > "$ENCRYPTION_SECRET_FILE"
|
||||
chmod 600 "$ENCRYPTION_SECRET_FILE"
|
||||
echo "✅ ENCRYPTION_SECRET generated and saved to $ENCRYPTION_SECRET_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# === DATABASE INITIALIZATION ===
|
||||
DB_PATH=$(echo "$DATABASE_URL" | sed 's|^file:||')
|
||||
if [ ! -f "$DB_PATH" ]; then
|
||||
echo "Database not found. It will be created and initialized via Drizzle migrations on first app startup..."
|
||||
touch "$DB_PATH"
|
||||
else
|
||||
echo "Database already exists, Drizzle will check for pending migrations on startup..."
|
||||
fi
|
||||
|
||||
# === STARTUP SCRIPTS ===
|
||||
# Initialize configuration from environment variables
|
||||
echo "Checking for environment configuration..."
|
||||
if [ -f "dist/scripts/startup-env-config.js" ]; then
|
||||
echo "Loading configuration from environment variables..."
|
||||
${pkgs.bun}/bin/bun dist/scripts/startup-env-config.js && \
|
||||
echo "✅ Environment configuration loaded successfully" || \
|
||||
echo "⚠️ Environment configuration loading completed with warnings"
|
||||
fi
|
||||
|
||||
# Run startup recovery
|
||||
echo "Running startup recovery..."
|
||||
if [ -f "dist/scripts/startup-recovery.js" ]; then
|
||||
${pkgs.bun}/bin/bun dist/scripts/startup-recovery.js --timeout=30000 && \
|
||||
echo "✅ Startup recovery completed successfully" || \
|
||||
echo "⚠️ Startup recovery completed with warnings"
|
||||
fi
|
||||
|
||||
# Run repository status repair
|
||||
echo "Running repository status repair..."
|
||||
if [ -f "dist/scripts/repair-mirrored-repos.js" ]; then
|
||||
${pkgs.bun}/bin/bun dist/scripts/repair-mirrored-repos.js --startup && \
|
||||
echo "✅ Repository status repair completed successfully" || \
|
||||
echo "⚠️ Repository status repair completed with warnings"
|
||||
fi
|
||||
|
||||
# === SIGNAL HANDLING ===
|
||||
shutdown_handler() {
|
||||
echo "🛑 Received shutdown signal, forwarding to application..."
|
||||
if [ ! -z "$APP_PID" ]; then
|
||||
kill -TERM "$APP_PID" 2>/dev/null || true
|
||||
wait "$APP_PID" 2>/dev/null || true
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap 'shutdown_handler' TERM INT HUP
|
||||
|
||||
# === START APPLICATION ===
|
||||
echo "Starting Gitea Mirror..."
|
||||
echo "Access the web interface at $BETTER_AUTH_URL"
|
||||
${pkgs.bun}/bin/bun dist/server/entry.mjs &
|
||||
APP_PID=$!
|
||||
|
||||
wait "$APP_PID"
|
||||
EOF
|
||||
chmod +x $out/bin/gitea-mirror
|
||||
|
||||
# Create database management helper
|
||||
cat > $out/bin/gitea-mirror-db <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
export DATA_DIR=''${DATA_DIR:-"$HOME/.local/share/gitea-mirror"}
|
||||
mkdir -p "$DATA_DIR"
|
||||
cd $out/lib/gitea-mirror
|
||||
exec ${pkgs.bun}/bin/bun scripts/manage-db.ts "$@"
|
||||
EOF
|
||||
chmod +x $out/bin/gitea-mirror-db
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Self-hosted GitHub to Gitea mirroring service";
|
||||
homepage = "https://github.com/RayLabsHQ/gitea-mirror";
|
||||
license = licenses.mit;
|
||||
maintainers = [ ];
|
||||
platforms = platforms.linux ++ platforms.darwin;
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
default = gitea-mirror;
|
||||
gitea-mirror = gitea-mirror;
|
||||
};
|
||||
|
||||
# Development shell
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
bun
|
||||
sqlite
|
||||
openssl
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "🚀 Gitea Mirror development environment"
|
||||
echo ""
|
||||
echo "Quick start:"
|
||||
echo " bun install # Install dependencies"
|
||||
echo " bun run dev # Start development server"
|
||||
echo " bun run build # Build for production"
|
||||
echo ""
|
||||
echo "Database:"
|
||||
echo " bun run manage-db init # Initialize database"
|
||||
echo " bun run db:studio # Open Drizzle Studio"
|
||||
'';
|
||||
};
|
||||
|
||||
# NixOS module
|
||||
nixosModules.default = { config, lib, pkgs, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.gitea-mirror;
|
||||
in {
|
||||
options.services.gitea-mirror = {
|
||||
enable = mkEnableOption "Gitea Mirror service";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = self.packages.${system}.default;
|
||||
description = "The Gitea Mirror package to use";
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/gitea-mirror";
|
||||
description = "Directory to store data and database";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "gitea-mirror";
|
||||
description = "User account under which Gitea Mirror runs";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "gitea-mirror";
|
||||
description = "Group under which Gitea Mirror runs";
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "0.0.0.0";
|
||||
description = "Host to bind to";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 4321;
|
||||
description = "Port to listen on";
|
||||
};
|
||||
|
||||
betterAuthUrl = mkOption {
|
||||
type = types.str;
|
||||
default = "http://localhost:4321";
|
||||
description = "Better Auth URL (external URL of the service)";
|
||||
};
|
||||
|
||||
betterAuthTrustedOrigins = mkOption {
|
||||
type = types.str;
|
||||
default = "http://localhost:4321";
|
||||
description = "Comma-separated list of trusted origins for Better Auth";
|
||||
};
|
||||
|
||||
mirrorIssueConcurrency = mkOption {
|
||||
type = types.int;
|
||||
default = 3;
|
||||
description = "Number of concurrent issue mirror operations (set to 1 for perfect ordering)";
|
||||
};
|
||||
|
||||
mirrorPullRequestConcurrency = mkOption {
|
||||
type = types.int;
|
||||
default = 5;
|
||||
description = "Number of concurrent PR mirror operations (set to 1 for perfect ordering)";
|
||||
};
|
||||
|
||||
environmentFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to file containing environment variables.
|
||||
Only needed if you want to set BETTER_AUTH_SECRET or ENCRYPTION_SECRET manually.
|
||||
Otherwise, secrets will be auto-generated and stored in the data directory.
|
||||
|
||||
Example:
|
||||
BETTER_AUTH_SECRET=your-32-character-secret-here
|
||||
ENCRYPTION_SECRET=your-encryption-secret-here
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Open the firewall for the specified port";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
users.users.${cfg.user} = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
home = cfg.dataDir;
|
||||
createHome = true;
|
||||
};
|
||||
|
||||
users.groups.${cfg.group} = {};
|
||||
|
||||
systemd.services.gitea-mirror = {
|
||||
description = "Gitea Mirror - GitHub to Gitea mirroring service";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
environment = {
|
||||
DATA_DIR = cfg.dataDir;
|
||||
DATABASE_URL = "file:${cfg.dataDir}/gitea-mirror.db";
|
||||
HOST = cfg.host;
|
||||
PORT = toString cfg.port;
|
||||
NODE_ENV = "production";
|
||||
BETTER_AUTH_URL = cfg.betterAuthUrl;
|
||||
BETTER_AUTH_TRUSTED_ORIGINS = cfg.betterAuthTrustedOrigins;
|
||||
PUBLIC_BETTER_AUTH_URL = cfg.betterAuthUrl;
|
||||
MIRROR_ISSUE_CONCURRENCY = toString cfg.mirrorIssueConcurrency;
|
||||
MIRROR_PULL_REQUEST_CONCURRENCY = toString cfg.mirrorPullRequestConcurrency;
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStart = "${cfg.package}/bin/gitea-mirror";
|
||||
Restart = "always";
|
||||
RestartSec = "10s";
|
||||
|
||||
# Security hardening
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
ReadWritePaths = [ cfg.dataDir ];
|
||||
|
||||
# Load environment file if specified (optional)
|
||||
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
|
||||
|
||||
# Graceful shutdown
|
||||
TimeoutStopSec = "30s";
|
||||
KillMode = "mixed";
|
||||
KillSignal = "SIGTERM";
|
||||
};
|
||||
};
|
||||
|
||||
# Health check timer (optional monitoring)
|
||||
systemd.timers.gitea-mirror-healthcheck = mkIf cfg.enable {
|
||||
description = "Gitea Mirror health check timer";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "5min";
|
||||
OnUnitActiveSec = "5min";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.gitea-mirror-healthcheck = mkIf cfg.enable {
|
||||
description = "Gitea Mirror health check";
|
||||
after = [ "gitea-mirror.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.curl}/bin/curl -f http://${cfg.host}:${toString cfg.port}/api/health || true";
|
||||
User = "nobody";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
) // {
|
||||
# Overlay for adding to nixpkgs
|
||||
overlays.default = final: prev: {
|
||||
gitea-mirror = self.packages.${final.system}.default;
|
||||
};
|
||||
};
|
||||
}
|
||||
44
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "gitea-mirror",
|
||||
"type": "module",
|
||||
"version": "3.8.11",
|
||||
"version": "3.9.2",
|
||||
"engines": {
|
||||
"bun": ">=1.2.9"
|
||||
},
|
||||
@@ -38,42 +38,42 @@
|
||||
"astro": "bunx --bun astro"
|
||||
},
|
||||
"overrides": {
|
||||
"@esbuild-kit/esm-loader": "npm:tsx@^4.20.5",
|
||||
"devalue": "^5.3.2"
|
||||
"@esbuild-kit/esm-loader": "npm:tsx@^4.20.6",
|
||||
"devalue": "^5.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.5",
|
||||
"@astrojs/mdx": "4.3.7",
|
||||
"@astrojs/mdx": "4.3.10",
|
||||
"@astrojs/node": "9.5.0",
|
||||
"@astrojs/react": "^4.4.0",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@better-auth/sso": "1.4.0-beta.12",
|
||||
"@octokit/plugin-throttling": "^11.0.2",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@octokit/plugin-throttling": "^11.0.3",
|
||||
"@octokit/rest": "^22.0.1",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-avatar": "^1.1.11",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-hover-card": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-progress": "^1.1.8",
|
||||
"@radix-ui/react-radio-group": "^1.3.8",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.2.6",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.8",
|
||||
"@tailwindcss/vite": "^4.1.15",
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tanstack/react-virtual": "^3.13.12",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"astro": "^5.14.8",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"astro": "^5.15.4",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"buffer": "^6.0.3",
|
||||
"better-auth": "1.4.0-beta.13",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
@@ -81,17 +81,17 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-orm": "^0.44.6",
|
||||
"drizzle-orm": "^0.44.7",
|
||||
"fuse.js": "^7.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.546.0",
|
||||
"lucide-react": "^0.553.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.15",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5.9.3",
|
||||
"uuid": "^13.0.0",
|
||||
@@ -102,14 +102,14 @@
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@types/bcryptjs": "^3.0.0",
|
||||
"@types/bun": "^1.3.0",
|
||||
"@types/bun": "^1.3.1",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@vitejs/plugin-react": "^5.0.4",
|
||||
"drizzle-kit": "^0.31.5",
|
||||
"@vitejs/plugin-react": "^5.1.0",
|
||||
"drizzle-kit": "^0.31.6",
|
||||
"jsdom": "^26.1.0",
|
||||
"tsx": "^4.20.6",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"packageManager": "bun@1.2.23"
|
||||
"packageManager": "bun@1.3.1"
|
||||
}
|
||||
|
||||
BIN
public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
3
public/favicon.svg
Normal file
|
After Width: | Height: | Size: 216 KiB |
141
src/lib/gitea.ts
@@ -1993,7 +1993,11 @@ export async function mirrorGitHubReleasesToGitea({
|
||||
let skippedCount = 0;
|
||||
|
||||
const getReleaseTimestamp = (release: typeof releases.data[number]) => {
|
||||
const sourceDate = release.created_at ?? release.published_at ?? "";
|
||||
// Use published_at first (when the release was published on GitHub)
|
||||
// Fall back to created_at (when the git tag was created) only if published_at is missing
|
||||
// This matches GitHub's sorting behavior and handles cases where multiple tags
|
||||
// point to the same commit but have different publish dates
|
||||
const sourceDate = release.published_at ?? release.created_at ?? "";
|
||||
const timestamp = sourceDate ? new Date(sourceDate).getTime() : 0;
|
||||
return Number.isFinite(timestamp) ? timestamp : 0;
|
||||
};
|
||||
@@ -2005,18 +2009,121 @@ export async function mirrorGitHubReleasesToGitea({
|
||||
.slice(0, releaseLimit)
|
||||
.sort((a, b) => getReleaseTimestamp(a) - getReleaseTimestamp(b));
|
||||
|
||||
console.log(`[Releases] Processing ${releasesToProcess.length} releases in chronological order (oldest to newest by published date)`);
|
||||
releasesToProcess.forEach((rel, idx) => {
|
||||
const publishedDate = new Date(rel.published_at || rel.created_at);
|
||||
const createdDate = new Date(rel.created_at);
|
||||
const dateInfo = rel.published_at !== rel.created_at
|
||||
? `published ${publishedDate.toISOString()} (tag created ${createdDate.toISOString()})`
|
||||
: `published ${publishedDate.toISOString()}`;
|
||||
console.log(`[Releases] ${idx + 1}. ${rel.tag_name} - ${dateInfo}`);
|
||||
});
|
||||
|
||||
// Check if existing releases in Gitea are in the wrong order
|
||||
// If so, we need to delete and recreate them to fix the ordering
|
||||
let needsRecreation = false;
|
||||
try {
|
||||
const existingReleasesResponse = await httpGet(
|
||||
`${config.giteaConfig.url}/api/v1/repos/${repoOwner}/${repoName}/releases?per_page=100`,
|
||||
{
|
||||
Authorization: `token ${decryptedConfig.giteaConfig.token}`,
|
||||
}
|
||||
).catch(() => null);
|
||||
|
||||
if (existingReleasesResponse && existingReleasesResponse.data && Array.isArray(existingReleasesResponse.data)) {
|
||||
const existingReleases = existingReleasesResponse.data;
|
||||
|
||||
if (existingReleases.length > 0) {
|
||||
console.log(`[Releases] Found ${existingReleases.length} existing releases in Gitea, checking chronological order...`);
|
||||
|
||||
// Create a map of tag_name to expected chronological index (0 = oldest, n = newest)
|
||||
const expectedOrder = new Map<string, number>();
|
||||
releasesToProcess.forEach((rel, idx) => {
|
||||
expectedOrder.set(rel.tag_name, idx);
|
||||
});
|
||||
|
||||
// Check if existing releases are in the correct order based on created_unix
|
||||
// Gitea sorts by created_unix DESC, so newer releases should have higher created_unix values
|
||||
const releasesThatShouldExist = existingReleases.filter(r => expectedOrder.has(r.tag_name));
|
||||
|
||||
if (releasesThatShouldExist.length > 1) {
|
||||
for (let i = 0; i < releasesThatShouldExist.length - 1; i++) {
|
||||
const current = releasesThatShouldExist[i];
|
||||
const next = releasesThatShouldExist[i + 1];
|
||||
|
||||
const currentExpectedIdx = expectedOrder.get(current.tag_name)!;
|
||||
const nextExpectedIdx = expectedOrder.get(next.tag_name)!;
|
||||
|
||||
// Since Gitea returns releases sorted by created_unix DESC:
|
||||
// - Earlier releases in the list should have HIGHER expected indices (newer)
|
||||
// - Later releases in the list should have LOWER expected indices (older)
|
||||
if (currentExpectedIdx < nextExpectedIdx) {
|
||||
console.log(`[Releases] ⚠️ Incorrect ordering detected: ${current.tag_name} (index ${currentExpectedIdx}) appears before ${next.tag_name} (index ${nextExpectedIdx})`);
|
||||
needsRecreation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsRecreation) {
|
||||
console.log(`[Releases] ⚠️ Releases are in incorrect chronological order. Will delete and recreate all releases.`);
|
||||
|
||||
// Delete all existing releases that we're about to recreate
|
||||
for (const existingRelease of releasesThatShouldExist) {
|
||||
try {
|
||||
console.log(`[Releases] Deleting incorrectly ordered release: ${existingRelease.tag_name}`);
|
||||
await httpDelete(
|
||||
`${config.giteaConfig.url}/api/v1/repos/${repoOwner}/${repoName}/releases/${existingRelease.id}`,
|
||||
{
|
||||
Authorization: `token ${decryptedConfig.giteaConfig.token}`,
|
||||
}
|
||||
);
|
||||
} catch (deleteError) {
|
||||
console.error(`[Releases] Failed to delete release ${existingRelease.tag_name}: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[Releases] ✅ Deleted ${releasesThatShouldExist.length} releases. Will recreate in correct chronological order.`);
|
||||
} else {
|
||||
console.log(`[Releases] ✅ Existing releases are in correct chronological order.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (orderCheckError) {
|
||||
console.warn(`[Releases] Could not verify release order: ${orderCheckError instanceof Error ? orderCheckError.message : String(orderCheckError)}`);
|
||||
// Continue with normal processing
|
||||
}
|
||||
|
||||
for (const release of releasesToProcess) {
|
||||
try {
|
||||
// Check if release already exists
|
||||
const existingReleasesResponse = await httpGet(
|
||||
// Check if release already exists (skip check if we just deleted all releases)
|
||||
const existingReleasesResponse = needsRecreation ? null : await httpGet(
|
||||
`${config.giteaConfig.url}/api/v1/repos/${repoOwner}/${repoName}/releases/tags/${release.tag_name}`,
|
||||
{
|
||||
Authorization: `token ${decryptedConfig.giteaConfig.token}`,
|
||||
}
|
||||
).catch(() => null);
|
||||
|
||||
const releaseNote = release.body || "";
|
||||
|
||||
// Prepare release body with GitHub original date header
|
||||
const githubPublishedDate = release.published_at || release.created_at;
|
||||
const githubTagCreatedDate = release.created_at;
|
||||
|
||||
let githubDateHeader = '';
|
||||
if (githubPublishedDate) {
|
||||
githubDateHeader = `> 📅 **Originally published on GitHub:** ${new Date(githubPublishedDate).toUTCString()}`;
|
||||
|
||||
// If the tag was created on a different date than the release was published,
|
||||
// show both dates (helps with repos that create multiple tags from the same commit)
|
||||
if (release.published_at && release.created_at && release.published_at !== release.created_at) {
|
||||
githubDateHeader += `\n> 🏷️ **Git tag created:** ${new Date(githubTagCreatedDate).toUTCString()}`;
|
||||
}
|
||||
|
||||
githubDateHeader += '\n\n';
|
||||
}
|
||||
|
||||
const originalReleaseNote = release.body || "";
|
||||
const releaseNote = githubDateHeader + originalReleaseNote;
|
||||
|
||||
if (existingReleasesResponse) {
|
||||
// Update existing release if the changelog/body differs
|
||||
const existingRelease = existingReleasesResponse.data;
|
||||
@@ -2039,9 +2146,11 @@ export async function mirrorGitHubReleasesToGitea({
|
||||
Authorization: `token ${decryptedConfig.giteaConfig.token}`,
|
||||
}
|
||||
);
|
||||
|
||||
if (releaseNote) {
|
||||
console.log(`[Releases] Updated changelog for ${release.tag_name} (${releaseNote.length} characters)`);
|
||||
|
||||
if (originalReleaseNote) {
|
||||
console.log(`[Releases] Updated changelog for ${release.tag_name} (${originalReleaseNote.length} characters + GitHub date header)`);
|
||||
} else {
|
||||
console.log(`[Releases] Updated release ${release.tag_name} with GitHub date header`);
|
||||
}
|
||||
mirroredCount++;
|
||||
} else {
|
||||
@@ -2051,9 +2160,11 @@ export async function mirrorGitHubReleasesToGitea({
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create new release with changelog/body content
|
||||
if (releaseNote) {
|
||||
console.log(`[Releases] Including changelog for ${release.tag_name} (${releaseNote.length} characters)`);
|
||||
// Create new release with changelog/body content (includes GitHub date header)
|
||||
if (originalReleaseNote) {
|
||||
console.log(`[Releases] Including changelog for ${release.tag_name} (${originalReleaseNote.length} characters + GitHub date header)`);
|
||||
} else {
|
||||
console.log(`[Releases] Creating release ${release.tag_name} with GitHub date header (no changelog)`);
|
||||
}
|
||||
|
||||
const createReleaseResponse = await httpPost(
|
||||
@@ -2121,8 +2232,14 @@ export async function mirrorGitHubReleasesToGitea({
|
||||
}
|
||||
|
||||
mirroredCount++;
|
||||
const noteInfo = releaseNote ? ` with ${releaseNote.length} character changelog` : " without changelog";
|
||||
const noteInfo = originalReleaseNote ? ` with ${originalReleaseNote.length} character changelog` : " without changelog";
|
||||
console.log(`[Releases] Successfully mirrored release: ${release.tag_name}${noteInfo}`);
|
||||
|
||||
// Add delay to ensure proper timestamp ordering in Gitea
|
||||
// Gitea sorts releases by created_unix DESC, and all releases created in quick succession
|
||||
// will have nearly identical timestamps. The 1-second delay ensures proper chronological order.
|
||||
console.log(`[Releases] Waiting 1 second to ensure proper timestamp ordering in Gitea...`);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
} catch (error) {
|
||||
console.error(`[Releases] Failed to mirror release ${release.tag_name}: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^4.3.7",
|
||||
"@astrojs/react": "^4.4.0",
|
||||
"@astrojs/mdx": "^4.3.10",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@splinetool/react-spline": "^4.1.0",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"astro": "^5.14.8",
|
||||
"astro": "^5.15.4",
|
||||
"canvas-confetti": "^1.9.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
|
||||
70
www/pnpm-lock.yaml
generated
@@ -9,11 +9,11 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@astrojs/mdx':
|
||||
specifier: ^4.3.7
|
||||
version: 4.3.7(astro@5.14.8(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3))
|
||||
specifier: ^4.3.10
|
||||
version: 4.3.10(astro@5.15.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3))
|
||||
'@astrojs/react':
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0(@types/node@24.7.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
specifier: ^4.4.2
|
||||
version: 4.4.2(@types/node@24.7.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
'@radix-ui/react-icons':
|
||||
specifier: ^1.3.2
|
||||
version: 1.3.2(react@19.2.0)
|
||||
@@ -28,7 +28,7 @@ importers:
|
||||
version: 1.10.85
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.15
|
||||
version: 4.1.15(vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
version: 4.1.15(vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
'@types/canvas-confetti':
|
||||
specifier: ^1.9.0
|
||||
version: 1.9.0
|
||||
@@ -39,8 +39,8 @@ importers:
|
||||
specifier: ^19.2.2
|
||||
version: 19.2.2(@types/react@19.2.2)
|
||||
astro:
|
||||
specifier: ^5.14.8
|
||||
version: 5.14.8(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3)
|
||||
specifier: ^5.15.4
|
||||
version: 5.15.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3)
|
||||
canvas-confetti:
|
||||
specifier: ^1.9.3
|
||||
version: 1.9.3
|
||||
@@ -85,8 +85,8 @@ packages:
|
||||
'@astrojs/markdown-remark@6.3.8':
|
||||
resolution: {integrity: sha512-uFNyFWadnULWK2cOw4n0hLKeu+xaVWeuECdP10cQ3K2fkybtTlhb7J7TcScdjmS8Yps7oje9S/ehYMfZrhrgCg==}
|
||||
|
||||
'@astrojs/mdx@4.3.7':
|
||||
resolution: {integrity: sha512-5SRmvMyT/UMWaU2eoD+htnXtE2mUZZEH2K/nEzhuEy+iCsOSuS/DUry59WuKUJRQETi1mgJFdNR4dZLJHYVuRA==}
|
||||
'@astrojs/mdx@4.3.10':
|
||||
resolution: {integrity: sha512-2T5+XIr7PMqMeXhRofXY5NlY4lA0Km+wkfsqmr9lq5KXUHpGlKPQ9dlDZJP9E/CtljJyEBNS17zq66LrIJ1tiQ==}
|
||||
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
|
||||
peerDependencies:
|
||||
astro: ^5.0.0
|
||||
@@ -95,8 +95,8 @@ packages:
|
||||
resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
|
||||
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
|
||||
|
||||
'@astrojs/react@4.4.0':
|
||||
resolution: {integrity: sha512-RzblkVImAFdV1C0AWsSWzS70Z0FMtW2p0XXkNYu3QePfyVJta3JIy8m8jY8271etaCZtpFjsE2UaiHGZIBm6nw==}
|
||||
'@astrojs/react@4.4.2':
|
||||
resolution: {integrity: sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ==}
|
||||
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.50 || ^18.0.21 || ^19.0.0
|
||||
@@ -886,8 +886,8 @@ packages:
|
||||
resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==}
|
||||
hasBin: true
|
||||
|
||||
astro@5.14.8:
|
||||
resolution: {integrity: sha512-nKqCLs7BFvGQL9QWQOUqxHhlHtV0UMLXz1ANJygozvjcexBWS7FYkWI2LzRPMNYmbW4msIWNWnX2RvLdvI5Cnw==}
|
||||
astro@5.15.4:
|
||||
resolution: {integrity: sha512-0g/68hLHEJZF2nYUcZM5O0kOnzCsCIf8eA9+0jfBAxp4ycujrIHRgIOdZCFKL9GoTsn8AypWbziypH5aEIF+aA==}
|
||||
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1281,10 +1281,6 @@ packages:
|
||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
kleur@4.1.5:
|
||||
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
@@ -1996,8 +1992,8 @@ packages:
|
||||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
vite@6.3.6:
|
||||
resolution: {integrity: sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==}
|
||||
vite@6.4.1:
|
||||
resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
|
||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -2135,16 +2131,16 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@astrojs/mdx@4.3.7(astro@5.14.8(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3))':
|
||||
'@astrojs/mdx@4.3.10(astro@5.15.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3))':
|
||||
dependencies:
|
||||
'@astrojs/markdown-remark': 6.3.8
|
||||
'@mdx-js/mdx': 3.1.1
|
||||
acorn: 8.15.0
|
||||
astro: 5.14.8(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3)
|
||||
astro: 5.15.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3)
|
||||
es-module-lexer: 1.7.0
|
||||
estree-util-visit: 2.0.0
|
||||
hast-util-to-html: 9.0.5
|
||||
kleur: 4.1.5
|
||||
picocolors: 1.1.1
|
||||
rehype-raw: 7.0.0
|
||||
remark-gfm: 4.0.1
|
||||
remark-smartypants: 3.0.2
|
||||
@@ -2158,15 +2154,15 @@ snapshots:
|
||||
dependencies:
|
||||
prismjs: 1.30.0
|
||||
|
||||
'@astrojs/react@4.4.0(@types/node@24.7.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
'@astrojs/react@4.4.2(@types/node@24.7.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||
dependencies:
|
||||
'@types/react': 19.2.2
|
||||
'@types/react-dom': 19.2.2(@types/react@19.2.2)
|
||||
'@vitejs/plugin-react': 4.7.0(vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
'@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
ultrahtml: 1.6.0
|
||||
vite: 6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
vite: 6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
@@ -2738,12 +2734,12 @@ snapshots:
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.15
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.1.15
|
||||
|
||||
'@tailwindcss/vite@4.1.15(vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))':
|
||||
'@tailwindcss/vite@4.1.15(vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.1.15
|
||||
'@tailwindcss/oxide': 4.1.15
|
||||
tailwindcss: 4.1.15
|
||||
vite: 6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
vite: 6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
|
||||
'@types/babel__core@7.20.5':
|
||||
dependencies:
|
||||
@@ -2816,7 +2812,7 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
|
||||
'@vitejs/plugin-react@4.7.0(vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))':
|
||||
'@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.0
|
||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0)
|
||||
@@ -2824,7 +2820,7 @@ snapshots:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.27
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.17.0
|
||||
vite: 6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
vite: 6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -2857,7 +2853,7 @@ snapshots:
|
||||
|
||||
astring@1.9.0: {}
|
||||
|
||||
astro@5.14.8(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3):
|
||||
astro@5.15.4(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.52.4)(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@astrojs/compiler': 2.13.0
|
||||
'@astrojs/internal-helpers': 0.7.4
|
||||
@@ -2891,7 +2887,6 @@ snapshots:
|
||||
http-cache-semantics: 4.2.0
|
||||
import-meta-resolve: 4.2.0
|
||||
js-yaml: 4.1.0
|
||||
kleur: 4.1.5
|
||||
magic-string: 0.30.19
|
||||
magicast: 0.3.5
|
||||
mrmime: 2.0.1
|
||||
@@ -2899,6 +2894,7 @@ snapshots:
|
||||
p-limit: 6.2.0
|
||||
p-queue: 8.1.1
|
||||
package-manager-detector: 1.4.0
|
||||
picocolors: 1.1.1
|
||||
picomatch: 4.0.3
|
||||
prompts: 2.4.2
|
||||
rehype: 13.0.2
|
||||
@@ -2913,8 +2909,8 @@ snapshots:
|
||||
unist-util-visit: 5.0.0
|
||||
unstorage: 1.17.1
|
||||
vfile: 6.0.3
|
||||
vite: 6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
vitefu: 1.1.1(vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
vite: 6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
vitefu: 1.1.1(vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2))
|
||||
xxhash-wasm: 1.1.0
|
||||
yargs-parser: 21.1.1
|
||||
yocto-spinner: 0.2.3
|
||||
@@ -3411,8 +3407,6 @@ snapshots:
|
||||
|
||||
kleur@3.0.3: {}
|
||||
|
||||
kleur@4.1.5: {}
|
||||
|
||||
lightningcss-android-arm64@1.30.2:
|
||||
optional: true
|
||||
|
||||
@@ -4452,7 +4446,7 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2):
|
||||
vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2):
|
||||
dependencies:
|
||||
esbuild: 0.25.10
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -4466,9 +4460,9 @@ snapshots:
|
||||
jiti: 2.6.1
|
||||
lightningcss: 1.30.2
|
||||
|
||||
vitefu@1.1.1(vite@6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)):
|
||||
vitefu@1.1.1(vite@6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)):
|
||||
optionalDependencies:
|
||||
vite: 6.3.6(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
vite: 6.4.1(@types/node@24.7.1)(jiti@2.6.1)(lightningcss@1.30.2)
|
||||
|
||||
web-namespaces@2.0.1: {}
|
||||
|
||||
|
||||
BIN
www/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
3
www/public/favicon.svg
Normal file
|
After Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 338 KiB After Width: | Height: | Size: 330 KiB |
138
www/src/components/FAQ.astro
Normal file
@@ -0,0 +1,138 @@
|
||||
---
|
||||
import { HelpCircle } from 'lucide-react';
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: "What is Gitea Mirror and why do I need it?",
|
||||
answer: "Gitea Mirror is a self-hosted tool that automatically backs up your GitHub repositories to your own Gitea server. You need it because GitHub outages, account issues, or policy changes can lock you out of your code. With Gitea Mirror, you own your backups completely—no monthly fees, no third-party storage, just full control over your repository history, issues, pull requests, and releases."
|
||||
},
|
||||
{
|
||||
question: "How is this different from BackHub or Rewind?",
|
||||
answer: "BackHub and Rewind are cloud services that cost $600-2400/year and store your code on their servers. Gitea Mirror is free, open source, and runs on your own infrastructure. You pay $0/month and have complete data ownership. The tradeoff: you manage the infrastructure yourself, while cloud services are fully managed."
|
||||
},
|
||||
{
|
||||
question: "Does Gitea Mirror backup issues, pull requests, and releases?",
|
||||
answer: "Yes! Enable 'Mirror metadata' in settings to backup issues with comments, labels, and assignees. Pull requests are mirrored as enriched issues with full metadata, commit history, and file changes (Gitea's API doesn't support creating PRs from external sources). Releases, including binary assets, and wiki pages are also backed up when enabled."
|
||||
},
|
||||
{
|
||||
question: "How long does setup take?",
|
||||
answer: "15-20 minutes with Docker. Run 'docker compose -f docker-compose.alt.yml up -d', visit localhost:4321, create an account, paste your GitHub and Gitea tokens, select repos to backup—done. The Proxmox LXC one-liner is even faster. No complex configuration files or manual scripting required."
|
||||
},
|
||||
{
|
||||
question: "What happens if GitHub goes down or I lose access?",
|
||||
answer: "You can immediately clone from your Gitea server instead. Your local backups include full commit history, branches, tags, issues, releases—everything. Recovery time is typically under 2 minutes (just point git to your Gitea URL). This is why it's called disaster recovery, not just mirroring."
|
||||
},
|
||||
{
|
||||
question: "How often does it sync with GitHub?",
|
||||
answer: "Configurable from every 15 minutes to once per day (or longer). Most users choose 1-8 hours based on how fresh they want backups. The scheduler auto-discovers new repos and respects per-repo intervals, unlike Gitea's built-in mirroring which defaults to 24 hours."
|
||||
},
|
||||
{
|
||||
question: "Can I backup starred repositories?",
|
||||
answer: "Yes! Gitea Mirror can automatically backup all your GitHub stars into a dedicated Gitea organization. Perfect for preserving important open source projects before they disappear (projects get deleted, renamed, or removed all the time)."
|
||||
},
|
||||
{
|
||||
question: "What are the system requirements?",
|
||||
answer: "Minimal: 2 vCPU, 2GB RAM, 5-10GB storage (grows with repo count). Runs on Docker, Kubernetes, Proxmox LXC, or bare metal. Works on AMD64 and ARM64 (Raspberry Pi compatible). A small homelab server or cheap VPS is plenty for personal use."
|
||||
},
|
||||
{
|
||||
question: "Is my GitHub token stored securely?",
|
||||
answer: "Yes. All GitHub and Gitea tokens are encrypted at rest using AES-256-GCM. Even if someone gains access to the SQLite database, they can't read your tokens without the encryption key. Use the ENCRYPTION_SECRET environment variable for additional security."
|
||||
},
|
||||
{
|
||||
question: "Can I backup private repositories?",
|
||||
answer: "Absolutely. Just use a GitHub personal access token (classic) with 'repo' scope enabled. Gitea Mirror will backup all repositories you have access to—public, private, and internal."
|
||||
},
|
||||
{
|
||||
question: "What if I have multiple GitHub organizations?",
|
||||
answer: "Gitea Mirror supports multiple organizations with flexible destination strategies: preserve GitHub structure in Gitea, consolidate into a single org, or use mixed mode (personal repos in one place, org repos preserve structure). Edit individual organization destinations via the dashboard."
|
||||
},
|
||||
{
|
||||
question: "Does it support Git LFS (large files)?",
|
||||
answer: "Yes! Enable 'Mirror LFS' in settings. Make sure your Gitea server has LFS enabled (LFS_START_SERVER = true) and Git v2.1.2+. Large assets like videos, datasets, and binaries are backed up alongside your code."
|
||||
},
|
||||
{
|
||||
question: "How do I restore from backup?",
|
||||
answer: "Simple: 'git clone https://your-gitea-server/owner/repo.git'. Your full history, branches, and tags are there. For issues/PRs/releases, they're already in Gitea's web interface. For complete disaster recovery, restore the data volume to a fresh Gitea Mirror instance—everything (config, sync history) is preserved."
|
||||
},
|
||||
{
|
||||
question: "Can I run this alongside a cloud backup service?",
|
||||
answer: "Yes! Many users run Gitea Mirror for local/warm backups while using cloud services for offsite redundancy. Best of both worlds: instant local recovery and geographic disaster protection. Totally compatible."
|
||||
},
|
||||
{
|
||||
question: "Is this enterprise-ready with SLA guarantees?",
|
||||
answer: "No. Gitea Mirror is a community open source project—no 24/7 support, no compliance certifications, no guaranteed uptime. It's perfect for homelabs, indie developers, and small teams comfortable with self-hosting. If you need enterprise SLAs, consider commercial solutions like BackHub or GitHub Enterprise Backup."
|
||||
}
|
||||
];
|
||||
|
||||
// Generate FAQ schema for SEO
|
||||
const faqSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": faqs.map(faq => ({
|
||||
"@type": "Question",
|
||||
"name": faq.question,
|
||||
"acceptedAnswer": {
|
||||
"@type": "Answer",
|
||||
"text": faq.answer
|
||||
}
|
||||
}))
|
||||
};
|
||||
---
|
||||
|
||||
<section id="faq" class="py-16 sm:py-24 px-4 sm:px-6 lg:px-8 bg-muted/30">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="text-center mb-12 sm:mb-16">
|
||||
<span class="inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-semibold uppercase tracking-widest text-muted-foreground mb-4">
|
||||
<HelpCircle className="w-4 h-4" />
|
||||
FAQ
|
||||
</span>
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight">
|
||||
Common Questions About GitHub Backups
|
||||
</h2>
|
||||
<p class="mt-4 text-base sm:text-lg text-muted-foreground">
|
||||
Everything you need to know about self-hosted repository backups with Gitea Mirror.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
{faqs.map((faq, index) => (
|
||||
<details class="group rounded-xl border bg-background/80 p-6 shadow-sm transition-all hover:shadow-md open:ring-1 open:ring-primary/20">
|
||||
<summary class="flex cursor-pointer items-start justify-between gap-4 font-semibold text-foreground list-none">
|
||||
<span class="text-left">{faq.question}</span>
|
||||
<svg
|
||||
class="h-5 w-5 flex-shrink-0 text-muted-foreground transition-transform group-open:rotate-180"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</summary>
|
||||
<p class="mt-4 text-sm sm:text-base text-muted-foreground leading-relaxed">
|
||||
{faq.answer}
|
||||
</p>
|
||||
</details>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="mt-12 text-center">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Still have questions?
|
||||
<a href="https://github.com/RayLabsHQ/gitea-mirror/discussions" class="text-primary hover:text-primary/80 font-medium transition-colors ml-1">
|
||||
Ask in our GitHub Discussions
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ Schema for SEO -->
|
||||
<script type="application/ld+json" set:html={JSON.stringify(faqSchema)} />
|
||||
|
||||
<style>
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button } from "./ui/button";
|
||||
import { ArrowRight, Shield, RefreshCw } from "lucide-react";
|
||||
import { ArrowRight, Shield, RefreshCw, HardDrive } from "lucide-react";
|
||||
import { GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||
import React, { Suspense } from 'react';
|
||||
|
||||
@@ -39,31 +39,30 @@ export function Hero() {
|
||||
<div className="clip-avoid w-full h-[16rem] md:h-[20rem] lg:h-[12rem] 2xl:h-[16rem]" aria-hidden="true"></div>
|
||||
<div className="max-w-7xl mx-auto pb-20 lg:pb-60 xl:pb-24 text-center w-full">
|
||||
<h1 className="pt-10 2xl:pt-20 text-3xl xs:text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold tracking-tight leading-tight">
|
||||
<span className="text-foreground">Keep Your Code</span>
|
||||
<span className="text-foreground">Backup Your GitHub</span>
|
||||
<br />
|
||||
<span className="text-gradient from-primary via-accent to-accent-purple">
|
||||
Safe & Synced
|
||||
To Self-Hosted Gitea
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="mt-4 sm:mt-6 text-base sm:text-lg md:text-xl text-muted-foreground max-w-3xl mx-auto px-4 z-20">
|
||||
Automatically mirror your GitHub repositories to self-hosted Gitea.
|
||||
Never lose access to your code with continuous backup and
|
||||
synchronization.
|
||||
Automatic, private, and free. Own your code history forever.
|
||||
Preserve issues, PRs, releases, and wiki in your own Gitea server.
|
||||
</p>
|
||||
|
||||
<div className="mt-6 sm:mt-8 flex flex-wrap items-center justify-center gap-3 text-xs sm:text-sm text-muted-foreground px-4 z-20">
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary">
|
||||
<Shield className="w-3 h-3 sm:w-4 sm:h-4" />
|
||||
<span className="font-medium">Self-Hosted</span>
|
||||
<HardDrive className="w-3 h-3 sm:w-4 sm:h-4" />
|
||||
<span className="font-medium">Self-Hosted Backup</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-accent/10 text-accent">
|
||||
<RefreshCw className="w-3 h-3 sm:w-4 sm:h-4" />
|
||||
<span className="font-medium">Auto-Sync</span>
|
||||
<span className="font-medium">Automated Syncing</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-accent-purple/10 text-accent-purple">
|
||||
<GitHubLogoIcon className="w-3 h-3 sm:w-4 sm:h-4" />
|
||||
<span className="font-medium">Open Source</span>
|
||||
<Shield className="w-3 h-3 sm:w-4 sm:h-4" />
|
||||
<span className="font-medium">$0/month</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export function Installation() {
|
||||
steps: [
|
||||
{
|
||||
title: "Clone the repository",
|
||||
command: "git clone https://github.com/RayLabsHQ/gitea-mirror.git\ncd gitea-mirror",
|
||||
command: "git clone https://github.com/RayLabsHQ/gitea-mirror.git && cd gitea-mirror",
|
||||
id: "docker-clone"
|
||||
},
|
||||
{
|
||||
@@ -166,4 +166,4 @@ export function Installation() {
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
254
www/src/pages/comparison/github-backup-tools.mdx
Normal file
@@ -0,0 +1,254 @@
|
||||
---
|
||||
layout: ../../layouts/UseCaseLayout.astro
|
||||
title: "GitHub Backup Tools Compared: Self-Hosted vs Cloud Solutions"
|
||||
description: "Compare Gitea Mirror with BackHub, Rewind, GitHub Enterprise Backup, and manual scripts. Choose the best GitHub backup solution for your needs."
|
||||
canonical: "https://gitea-mirror.com/comparison/github-backup-tools/"
|
||||
---
|
||||
|
||||
# GitHub Backup Tools Compared: Finding the Right Solution
|
||||
|
||||
## Why GitHub backups matter
|
||||
|
||||
GitHub hosts millions of repositories, but relying on a single platform comes with risks:
|
||||
|
||||
- **Outages**: GitHub experiences downtime (most recent: November 2024, October 2024, August 2024)
|
||||
- **Account issues**: DMCA takedowns, TOS violations, or account suspensions can lock you out
|
||||
- **Accidental deletions**: One wrong click and your repo history vanishes
|
||||
- **Company changes**: Microsoft's acquisition led to policy shifts many developers disagreed with
|
||||
- **Data sovereignty**: GDPR, HIPAA, or internal policies may require local data control
|
||||
|
||||
The question isn't *if* you need backups—it's *which solution* fits your workflow and budget.
|
||||
|
||||
## Comparison at a glance
|
||||
|
||||
| Feature | Gitea Mirror | BackHub | Rewind Backups | GitHub Enterprise Backup | Manual Scripts |
|
||||
|---------|--------------|---------|----------------|-------------------------|----------------|
|
||||
| **Cost/Year** | $0 | $600+ | $240+ | $21,000+ | $0 |
|
||||
| **Self-Hosted** | ✅ | ❌ | ❌ | Optional | ✅ |
|
||||
| **Setup Time** | 15 min | 5 min | 5 min | Days | 2+ hours |
|
||||
| **Metadata (Issues/PRs)** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Releases & Assets** | ✅ | ✅ | ✅ | ✅ | Partial |
|
||||
| **Wiki Backup** | ✅ | ✅ | ✅ | ✅ | Partial |
|
||||
| **Git LFS Support** | ✅ | ✅ | ✅ | ✅ | Manual |
|
||||
| **Auto-Discovery** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Scheduled Syncing** | ✅ | ✅ | ✅ | ✅ | Cron-based |
|
||||
| **Data Ownership** | ✅ Full | ❌ | ❌ | ✅ | ✅ Full |
|
||||
| **Restore Complexity** | Low | Medium | Medium | Low | High |
|
||||
| **Multi-Org Support** | ✅ | ✅ | ✅ | ✅ | Manual |
|
||||
| **Real-Time Dashboard** | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
|
||||
## Solution breakdown
|
||||
|
||||
### Gitea Mirror (Self-Hosted, Free)
|
||||
|
||||
**Best for**: Homelab enthusiasts, indie developers, privacy-conscious teams, cost-sensitive startups
|
||||
|
||||
**How it works**: Automatically mirrors your GitHub repositories to your own Gitea server using scheduled syncs. Preserves full history, metadata (issues, PRs as enriched issues, labels, milestones), releases, and wiki content.
|
||||
|
||||
**Pros**:
|
||||
- ✅ **Zero recurring costs** - Just your hosting/hardware
|
||||
- ✅ **Complete data ownership** - Everything stays on your infrastructure
|
||||
- ✅ **Privacy-first** - No third parties touch your code
|
||||
- ✅ **Customizable** - Open source, fork it, extend it
|
||||
- ✅ **Docker-friendly** - One command deployment
|
||||
- ✅ **Multi-arch support** - AMD64 and ARM64 (Raspberry Pi compatible)
|
||||
- ✅ **No vendor lock-in** - Standard Git repos, portable
|
||||
|
||||
**Cons**:
|
||||
- ❌ You manage the infrastructure (server, backups, updates)
|
||||
- ❌ Community support only (no SLA)
|
||||
- ❌ Requires basic Docker/server knowledge
|
||||
- ❌ You're responsible for Gitea security updates
|
||||
|
||||
**Ideal user**: "I run a homelab with Proxmox/Docker and want full control over my GitHub backups without paying monthly fees."
|
||||
|
||||
**Setup**:
|
||||
```bash
|
||||
docker compose -f docker-compose.alt.yml up -d
|
||||
# Visit http://localhost:4321, create account, add tokens
|
||||
```
|
||||
|
||||
### BackHub (Cloud, $50-200/month)
|
||||
|
||||
**Best for**: Teams wanting zero infrastructure management, compliance-focused organizations
|
||||
|
||||
**How it works**: SaaS platform that backs up GitHub orgs/repos to their cloud storage. Offers point-in-time recovery and compliance features.
|
||||
|
||||
**Pros**:
|
||||
- ✅ Fully managed (zero infrastructure)
|
||||
- ✅ SOC 2 compliant
|
||||
- ✅ Easy restore interface
|
||||
- ✅ Supports all GitHub features
|
||||
|
||||
**Cons**:
|
||||
- ❌ $600-2400/year minimum
|
||||
- ❌ Your code lives on their servers
|
||||
- ❌ Vendor lock-in for restore process
|
||||
- ❌ Pricing scales with repo count
|
||||
- ❌ No self-hosted option
|
||||
|
||||
**Ideal user**: "I need GitHub backups with compliance guarantees and don't want to manage servers."
|
||||
|
||||
### Rewind Backups (Cloud, $20-100/month)
|
||||
|
||||
**Best for**: Small teams, agencies managing client repos
|
||||
|
||||
**How it works**: Cloud backup service that snapshots GitHub data daily/hourly with web-based restore.
|
||||
|
||||
**Pros**:
|
||||
- ✅ Simple setup (OAuth connection)
|
||||
- ✅ User-friendly restore UI
|
||||
- ✅ Supports multiple SaaS platforms (not just GitHub)
|
||||
|
||||
**Cons**:
|
||||
- ❌ $240-1200/year
|
||||
- ❌ Cloud-only storage
|
||||
- ❌ Restore requires their platform
|
||||
- ❌ Limited to their backup schedule
|
||||
- ❌ No local/offline access
|
||||
|
||||
**Ideal user**: "I backup multiple SaaS tools and want one dashboard for everything."
|
||||
|
||||
### GitHub Enterprise Backup Utilities (Self-Hosted, Requires GHE)
|
||||
|
||||
**Best for**: Large enterprises already on GitHub Enterprise
|
||||
|
||||
**How it works**: Official GitHub tool for backing up GitHub Enterprise Server instances. Creates encrypted backup snapshots.
|
||||
|
||||
**Pros**:
|
||||
- ✅ Official GitHub tool
|
||||
- ✅ Enterprise-grade
|
||||
- ✅ Compliance-ready
|
||||
|
||||
**Cons**:
|
||||
- ❌ Requires GitHub Enterprise license ($21k+/year for 10 users)
|
||||
- ❌ Only works with Enterprise Server, not GitHub.com
|
||||
- ❌ Complex setup and maintenance
|
||||
- ❌ Overkill for small teams
|
||||
|
||||
**Ideal user**: "We're already paying for GitHub Enterprise and need official backup tooling."
|
||||
|
||||
### Manual Git Scripts (DIY, Free but Brittle)
|
||||
|
||||
**Best for**: Minimalists with few repos and technical expertise
|
||||
|
||||
**How it works**: Cron jobs that run `git clone --mirror` for each repo.
|
||||
|
||||
**Pros**:
|
||||
- ✅ Zero cost
|
||||
- ✅ Simple concept
|
||||
- ✅ No third-party dependencies
|
||||
|
||||
**Cons**:
|
||||
- ❌ No metadata backup (issues, PRs, releases lost)
|
||||
- ❌ Manual discovery of new repos
|
||||
- ❌ No LFS support without extra work
|
||||
- ❌ Fails silently (no health checks)
|
||||
- ❌ High maintenance overhead
|
||||
- ❌ No organization/bulk operations
|
||||
- ❌ Wiki requires separate cloning logic
|
||||
|
||||
**Ideal user**: "I have 2-3 repos and enjoy writing Bash scripts."
|
||||
|
||||
## Decision framework
|
||||
|
||||
### Choose Gitea Mirror if you:
|
||||
- Want $0 recurring costs
|
||||
- Run a homelab or have spare hardware
|
||||
- Value data ownership and privacy
|
||||
- Are comfortable with Docker/basic sysadmin tasks
|
||||
- Need to back up personal repos or small org (<50 repos)
|
||||
- Want to learn self-hosting skills
|
||||
|
||||
### Choose BackHub if you:
|
||||
- Have budget for managed services ($50-200/mo)
|
||||
- Need SOC 2 compliance
|
||||
- Want zero infrastructure management
|
||||
- Back up 10+ organizations
|
||||
- Require guaranteed SLA
|
||||
|
||||
### Choose Rewind if you:
|
||||
- Back up multiple SaaS tools (not just GitHub)
|
||||
- Have limited budget ($20-50/mo)
|
||||
- Want dead-simple restore UX
|
||||
- Don't need self-hosted storage
|
||||
|
||||
### Choose GitHub Enterprise Backup if you:
|
||||
- Already have GitHub Enterprise Server
|
||||
- Need official support contracts
|
||||
- Operate at enterprise scale (hundreds of users)
|
||||
- Have compliance requirements for official tooling
|
||||
|
||||
### Choose Manual Scripts if you:
|
||||
- Have <5 repos
|
||||
- Don't care about metadata/issues/PRs
|
||||
- Enjoy scripting and troubleshooting
|
||||
- Have time to maintain cron jobs
|
||||
|
||||
## Real-world cost comparison (5-year total)
|
||||
|
||||
Assuming 50 repositories, 10 active contributors:
|
||||
|
||||
| Solution | Year 1 | Year 5 Total | Notes |
|
||||
|----------|--------|--------------|-------|
|
||||
| **Gitea Mirror** | $0-50 | $0-250 | Only hardware/hosting costs (VPS: ~$50/yr) |
|
||||
| **BackHub** | $1,200 | $6,000 | Scales with repos |
|
||||
| **Rewind** | $600 | $3,000 | Mid-tier plan |
|
||||
| **GitHub Enterprise Backup** | $21,000+ | $105,000+ | Requires GHE license |
|
||||
| **Manual Scripts** | $0 | $0 | Plus hundreds of hours maintaining |
|
||||
|
||||
## Migration paths
|
||||
|
||||
### From cloud backup to Gitea Mirror
|
||||
1. Export backup data from your cloud provider (if supported)
|
||||
2. Deploy Gitea Mirror following the [backup playbook](/use-cases/backup-github-repositories/)
|
||||
3. Let Gitea Mirror rebuild from GitHub (preserves all metadata)
|
||||
4. Cancel cloud subscription once validated
|
||||
|
||||
### From manual scripts to Gitea Mirror
|
||||
1. Note your current repo list
|
||||
2. Deploy Gitea Mirror and connect GitHub
|
||||
3. Auto-import handles discovery
|
||||
4. Delete cron jobs once sync confirmed
|
||||
|
||||
### From Gitea Mirror to other solutions
|
||||
Your repos are standard Git mirrors—clone from Gitea and push to any other service. Zero lock-in.
|
||||
|
||||
## Frequently asked questions
|
||||
|
||||
### Can I use Gitea Mirror alongside a cloud backup service?
|
||||
|
||||
Absolutely! Gitea Mirror adds a self-hosted "warm backup" layer while cloud services provide offsite redundancy. Best of both worlds.
|
||||
|
||||
### What if my hardware fails?
|
||||
|
||||
Snapshot your Gitea Mirror data volume regularly using ZFS, Btrfs, or tools like Restic. Store snapshots offsite. The GitHub → Gitea Mirror sync is idempotent—spin up a new instance, restore data volume, and it resumes.
|
||||
|
||||
### How does Gitea Mirror compare for disaster recovery?
|
||||
|
||||
**RTO (Recovery Time Objective)**: Minutes—just `git clone` from your Gitea server.
|
||||
**RPO (Recovery Point Objective)**: Depends on sync interval (15 min - 24 hours typical).
|
||||
|
||||
Cloud services have similar RPO but may have slower RTO if you need to restore hundreds of repos through a web UI.
|
||||
|
||||
### Can I try Gitea Mirror without committing?
|
||||
|
||||
Yes! The Docker setup takes 15 minutes. Test with a few repos, evaluate, then scale or remove with `docker compose down -v`.
|
||||
|
||||
### Does Gitea Mirror work with GitHub Enterprise Cloud?
|
||||
|
||||
Yes, as long as you have API access and a personal access token. The GitHub API endpoint is configurable.
|
||||
|
||||
## Next steps
|
||||
|
||||
- **Ready to self-host?** Follow the [GitHub backup playbook](/use-cases/backup-github-repositories/)
|
||||
- **Need multi-tenant?** See [Proxmox LXC deployment](/use-cases/proxmox-lxc-homelab/) or [Kubernetes Helm chart](/use-cases/deploy-with-helm-chart/)
|
||||
- **Questions?** [Open a GitHub discussion](https://github.com/RayLabsHQ/gitea-mirror/discussions)
|
||||
|
||||
## Honest assessment
|
||||
|
||||
Gitea Mirror is **not** enterprise SaaS. There's no 24/7 support, no compliance certifications, no guaranteed uptime. It's a well-maintained open source project built by and for developers who value ownership and cost-effectiveness.
|
||||
|
||||
If you need a pager number when things break, choose a commercial solution. If you enjoy owning your infrastructure and solving problems, Gitea Mirror saves thousands of dollars annually while giving you complete control.
|
||||
|
||||
The best backup solution is the one you'll actually use and test. Choose based on your skills, budget, and risk tolerance—not marketing promises.
|
||||
@@ -8,44 +8,47 @@ import UseCases from '../components/UseCases.astro';
|
||||
import Screenshots from '../components/Screenshots.astro';
|
||||
import { Installation } from '../components/Installation';
|
||||
import { CTA } from '../components/CTA';
|
||||
import FAQ from '../components/FAQ.astro';
|
||||
import Footer from '../components/Footer.astro';
|
||||
|
||||
const siteUrl = 'https://gitea-mirror.com';
|
||||
const title = 'Gitea Mirror - Automated GitHub to Gitea Repository Mirroring & Backup';
|
||||
const description = 'Automatically mirror and backup your GitHub repositories to self-hosted Gitea. Keep your code safe with scheduled syncing, bulk operations, and real-time monitoring. Free and open source.';
|
||||
const keywords = 'github backup, gitea mirror, repository sync, github to gitea, git mirror, code backup, self-hosted git, repository migration, github mirror tool, gitea sync, automated backup, github repository backup, git repository mirror, self-hosted backup solution';
|
||||
const title = 'GitHub Backup Tool | Self-Hosted Repository Backup to Gitea';
|
||||
const description = 'Automatically backup GitHub repos to your own Gitea server. Preserve issues, PRs, releases & wiki. Self-hosted, Docker-ready. Free alternative to cloud backup services.';
|
||||
const keywords = 'github backup, github backup self hosted, github repository backup, backup github to nas, github disaster recovery, offline github backup, github backup docker, automatic github backup, github account backup, gitea mirror, self-hosted git backup, repository sync, github to gitea, git mirror, code backup, self-hosted backup solution';
|
||||
|
||||
// Structured data for SEO
|
||||
const structuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "SoftwareApplication",
|
||||
"name": "Gitea Mirror",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"applicationCategory": "BackupApplication",
|
||||
"operatingSystem": "Linux, macOS, Windows",
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "0",
|
||||
"priceCurrency": "USD"
|
||||
},
|
||||
"description": description,
|
||||
"description": "Automatic GitHub repository backup to self-hosted Gitea. Preserves complete history, issues, PRs, and releases. Free alternative to cloud backup services.",
|
||||
"url": siteUrl,
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "RayLabs",
|
||||
"url": "https://github.com/RayLabsHQ"
|
||||
},
|
||||
"softwareVersion": "2.22.0",
|
||||
"softwareVersion": "3.9.2",
|
||||
"screenshot": [
|
||||
`${siteUrl}/assets/dashboard.png`,
|
||||
`${siteUrl}/assets/repositories.png`,
|
||||
`${siteUrl}/assets/organisation.png`
|
||||
],
|
||||
"featureList": [
|
||||
"Automated repository mirroring",
|
||||
"Bulk organization sync",
|
||||
"Real-time monitoring",
|
||||
"Self-hosted solution",
|
||||
"Open source"
|
||||
"Automated scheduled backups",
|
||||
"Self-hosted (full data ownership)",
|
||||
"Metadata preservation (issues, PRs, releases, wiki)",
|
||||
"Docker support",
|
||||
"Multi-repository backup",
|
||||
"Git LFS support",
|
||||
"Free and open source"
|
||||
],
|
||||
"softwareRequirements": "Docker or Bun runtime"
|
||||
};
|
||||
@@ -127,6 +130,7 @@ const structuredData = {
|
||||
<UseCases />
|
||||
<Screenshots />
|
||||
<Installation client:load />
|
||||
<FAQ />
|
||||
<CTA client:load />
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
---
|
||||
layout: ../../layouts/UseCaseLayout.astro
|
||||
title: "Run Gitea Mirror inside a Proxmox LXC"
|
||||
description: "Provision the community-maintained Proxmox VE LXC container for Gitea Mirror and wire it into your homelab backup workflow."
|
||||
title: "Self-Hosted GitHub Backup on Proxmox LXC | Gitea Mirror Homelab Setup"
|
||||
description: "Deploy a dedicated GitHub backup appliance in your Proxmox homelab using the one-line LXC installer. Automatic syncing, snapshot-ready, homelab-optimized."
|
||||
canonical: "https://gitea-mirror.com/use-cases/proxmox-lxc-homelab/"
|
||||
---
|
||||
|
||||
# Run Gitea Mirror inside a Proxmox LXC
|
||||
# Self-Hosted GitHub Backup on Proxmox LXC
|
||||
|
||||
## Why run it on Proxmox
|
||||
## The Homelab GitHub Backup Appliance
|
||||
|
||||
When most of your homelab lives in Proxmox VE, the community LXC script is the fastest path from zero to a managed Gitea Mirror node. It handles Bun, systemd, persistent storage, and future upgrades so you can focus on keeping Git backups fresh.
|
||||
Running GitHub backups in your homelab means **complete data ownership** without monthly SaaS fees. When most of your infrastructure lives in Proxmox VE, the community LXC script is the fastest path from zero to a dedicated backup appliance.
|
||||
|
||||
It handles Bun runtime, systemd services, persistent storage, and future upgrades—so you can focus on keeping your GitHub history safe and synced locally. Perfect for homelabbers who want the peace of mind of offline backups without cloud dependencies.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||