mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-07 20:16:46 +03:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3f42624d8 | ||
|
|
d79e4fecf4 | ||
|
|
eb78f959c7 | ||
|
|
51e536c317 | ||
|
|
7af1f6da17 | ||
|
|
c7e310b340 | ||
|
|
23cfa45d89 | ||
|
|
b1346e8c77 | ||
|
|
6e673249dc |
@@ -1,3 +1,4 @@
|
||||
Evaluate all the updates being made.
|
||||
Make sure the user has clarified if its a major, minor or a patch release.
|
||||
Update the package.json first before you push the tag.
|
||||
Update CHANGELOG.md
|
||||
Use the chnages in the git log to determine if its a major, minor or a patch release.
|
||||
Update the package.json first before you push the tag.
|
||||
|
||||
BIN
.github/assets/configuration.png
vendored
BIN
.github/assets/configuration.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 945 KiB After Width: | Height: | Size: 891 KiB |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -5,6 +5,30 @@ All notable changes to the Gitea Mirror project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.14.0] - 2025-06-17
|
||||
|
||||
### Added
|
||||
- Enhanced UI components with @radix-ui/react-accordion dependency for improved configuration interface
|
||||
|
||||
### Fixed
|
||||
- Mirror strategies now properly route repositories based on selected strategy
|
||||
- Starred repositories now correctly go to the designated starred repos organization
|
||||
- Organization routing for single-org and flat-user strategies
|
||||
|
||||
### Improved
|
||||
- Documentation now explains all three mirror strategies (preserve, single-org, flat-user)
|
||||
- Added detailed mirror strategy configuration guide
|
||||
- Updated CLAUDE.md with mirror strategy architecture information
|
||||
- Enhanced Docker Compose development configuration
|
||||
|
||||
## [2.13.2] - 2025-06-15
|
||||
|
||||
### Improved
|
||||
- Enhanced documentation design and layout
|
||||
- Updated README with improved formatting and content
|
||||
|
||||
## [2.13.1] - 2025-06-15
|
||||
|
||||
### Added
|
||||
|
||||
@@ -79,6 +79,13 @@ export async function POST({ request }: APIContext) {
|
||||
- Tracks status in database
|
||||
- Supports scheduled automatic mirroring
|
||||
|
||||
6. **Mirror Strategies**: Three ways to organize repositories in Gitea:
|
||||
- **preserve**: Maintains GitHub structure (default)
|
||||
- **single-org**: All repos go to one organization
|
||||
- **flat-user**: All repos go under user account
|
||||
- Starred repos always go to separate organization (starredReposOrg)
|
||||
- Routing logic in `getGiteaRepoOwner()` function
|
||||
|
||||
### Database Schema (SQLite)
|
||||
- `users` - User accounts and authentication
|
||||
- `configs` - GitHub/Gitea connection settings
|
||||
|
||||
63
README.md
63
README.md
@@ -36,9 +36,9 @@ See the [LXC Container Deployment Guide](scripts/README-lxc.md).
|
||||
## ✨ Features
|
||||
|
||||
- 🔁 Sync public, private, or starred GitHub repos to Gitea
|
||||
- 🏢 Mirror entire organizations with structure preservation
|
||||
- 🏢 Mirror entire organizations with flexible organization strategies
|
||||
- 🐞 Optional mirroring of issues and labels
|
||||
- 🌟 Mirror your starred repositories
|
||||
- 🌟 Mirror your starred repositories to a dedicated organization
|
||||
- 🕹️ Modern user interface with toast notifications and smooth experience
|
||||
- 🧠 Smart filtering and job queue with detailed logs
|
||||
- 🛠️ Works with personal access tokens (GitHub + Gitea)
|
||||
@@ -167,36 +167,27 @@ docker compose up -d
|
||||
|
||||
See [Docker build documentation](./scripts/README-docker.md) for more details.
|
||||
|
||||
##### Using LXC Containers
|
||||
##### Using LXC Containers (Proxmox VE)
|
||||
|
||||
Gitea Mirror offers two deployment options for LXC containers:
|
||||
|
||||
**1. Proxmox VE (online, recommended for production)**
|
||||
For Proxmox VE users, Gitea Mirror can be deployed using the community-maintained script:
|
||||
|
||||
```bash
|
||||
# One-command installation on Proxmox VE
|
||||
# Uses the community-maintained script by Tobias ([CrazyWolf13](https://github.com/CrazyWolf13))
|
||||
# at [community-scripts/ProxmoxVE](https://github.com/community-scripts/ProxmoxVE)
|
||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/gitea-mirror.sh)"
|
||||
```
|
||||
|
||||
**2. Local testing (offline-friendly, works on developer laptops)**
|
||||
This community script:
|
||||
- Creates a privileged Alpine Linux LXC container
|
||||
- Installs Bun runtime environment
|
||||
- Clones and builds Gitea Mirror
|
||||
- Configures a systemd service for automatic startup
|
||||
- Sets up the application to run on port 4321
|
||||
|
||||
```bash
|
||||
# Download the script
|
||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-local.sh -o gitea-mirror-lxc-local.sh
|
||||
chmod +x gitea-mirror-lxc-local.sh
|
||||
> [!NOTE]
|
||||
> The script is maintained by the [Community Scripts for Proxmox VE](https://community-scripts.github.io/ProxmoxVE/) project.
|
||||
> For more information, visit the [Gitea Mirror script documentation](https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror).
|
||||
|
||||
# Run with your local repo directory
|
||||
sudo LOCAL_REPO_DIR=~/Development/gitea-mirror ./gitea-mirror-lxc-local.sh
|
||||
```
|
||||
|
||||
Both scripts:
|
||||
- Set up a privileged Ubuntu 22.04 LXC container
|
||||
- Install Bun runtime environment
|
||||
- Build the application
|
||||
- Configure a systemd service
|
||||
- Start the service automatically
|
||||
After installation, access Gitea Mirror at `http://<container-ip>:4321`
|
||||
|
||||
The application includes a health check endpoint at `/api/health` for monitoring.
|
||||
|
||||
@@ -326,6 +317,28 @@ Key configuration options include:
|
||||
> [!IMPORTANT]
|
||||
> **SQLite is the only database required for Gitea Mirror**, handling both data storage and real-time event notifications.
|
||||
|
||||
### Mirror Strategies
|
||||
|
||||
Gitea Mirror offers three flexible strategies for organizing your repositories in Gitea:
|
||||
|
||||
#### 1. **Preserve GitHub Structure** (Default)
|
||||
- Personal repositories → Your Gitea username
|
||||
- Organization repositories → Same organization name in Gitea
|
||||
- Maintains the exact structure from GitHub
|
||||
|
||||
#### 2. **Single Organization**
|
||||
- All repositories → One designated organization
|
||||
- Simplifies management by consolidating everything
|
||||
- Requires specifying a destination organization name
|
||||
|
||||
#### 3. **Flat User Structure**
|
||||
- All repositories → Your Gitea user account
|
||||
- No organizations needed
|
||||
- Simplest approach for personal use
|
||||
|
||||
> [!NOTE]
|
||||
> **Starred Repositories**: Regardless of the chosen strategy, starred repositories are always mirrored to a separate organization (default: "starred") to keep them organized separately from your own repositories.
|
||||
|
||||
## 🚀 Development
|
||||
|
||||
### Local Development Setup
|
||||
@@ -363,13 +376,13 @@ docker run -d \
|
||||
-e USER_UID=1000 \
|
||||
-e USER_GID=1000 \
|
||||
-e GITEA__database__DB_TYPE=sqlite3 \
|
||||
-e GITEA__database__PATH=/data/gitea.db \
|
||||
-e GITEA__database__PATH=/data/gitea/gitea.db \
|
||||
-e GITEA__server__DOMAIN=localhost \
|
||||
-e GITEA__server__ROOT_URL=http://localhost:3001/ \
|
||||
-e GITEA__server__SSH_DOMAIN=localhost \
|
||||
-e GITEA__server__SSH_PORT=2222 \
|
||||
-e GITEA__server__START_SSH_SERVER=true \
|
||||
-e GITEA__security__INSTALL_LOCK=true \
|
||||
-e GITEA__security__INSTALL_LOCK=false \
|
||||
-e GITEA__service__DISABLE_REGISTRATION=false \
|
||||
gitea/gitea:latest
|
||||
```
|
||||
|
||||
199
bun.lock
199
bun.lock
@@ -4,10 +4,12 @@
|
||||
"": {
|
||||
"name": "gitea-mirror",
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/mdx": "^4.3.0",
|
||||
"@astrojs/node": "^9.2.2",
|
||||
"@astrojs/react": "^4.3.0",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
@@ -46,6 +48,7 @@
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"tw-animate-css": "^1.3.4",
|
||||
"typescript": "^5.8.3",
|
||||
"uuid": "^11.1.0",
|
||||
"zod": "^3.25.64",
|
||||
},
|
||||
@@ -69,10 +72,14 @@
|
||||
|
||||
"@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="],
|
||||
|
||||
"@astrojs/check": ["@astrojs/check@0.9.4", "", { "dependencies": { "@astrojs/language-server": "^2.15.0", "chokidar": "^4.0.1", "kleur": "^4.1.5", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": "^5.0.0" }, "bin": { "astro-check": "dist/bin.js" } }, "sha512-IOheHwCtpUfvogHHsvu0AbeRZEnjJg3MopdLddkJE70mULItS/Vh37BHcI00mcOJcH1vhD3odbpvWokpxam7xA=="],
|
||||
|
||||
"@astrojs/compiler": ["@astrojs/compiler@2.12.2", "", {}, "sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw=="],
|
||||
|
||||
"@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="],
|
||||
|
||||
"@astrojs/language-server": ["@astrojs/language-server@2.15.4", "", { "dependencies": { "@astrojs/compiler": "^2.10.3", "@astrojs/yaml2ts": "^0.2.2", "@jridgewell/sourcemap-codec": "^1.4.15", "@volar/kit": "~2.4.7", "@volar/language-core": "~2.4.7", "@volar/language-server": "~2.4.7", "@volar/language-service": "~2.4.7", "fast-glob": "^3.2.12", "muggle-string": "^0.4.1", "volar-service-css": "0.0.62", "volar-service-emmet": "0.0.62", "volar-service-html": "0.0.62", "volar-service-prettier": "0.0.62", "volar-service-typescript": "0.0.62", "volar-service-typescript-twoslash-queries": "0.0.62", "volar-service-yaml": "0.0.62", "vscode-html-languageservice": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "bin/nodeServer.js" } }, "sha512-JivzASqTPR2bao9BWsSc/woPHH7OGSGc9aMxXL4U6egVTqBycB3ZHdBJPuOCVtcGLrzdWTosAqVPz1BVoxE0+A=="],
|
||||
|
||||
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.2", "", { "dependencies": { "@astrojs/internal-helpers": "0.6.1", "@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.1.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.2.1", "smol-toml": "^1.3.1", "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-bO35JbWpVvyKRl7cmSJD822e8YA8ThR/YbUsciWNA7yTcqpIAL2hJDToWP5KcZBWxGT6IOdOkHSXARSNZc4l/Q=="],
|
||||
|
||||
"@astrojs/mdx": ["@astrojs/mdx@4.3.0", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.2", "@mdx-js/mdx": "^3.1.0", "acorn": "^8.14.1", "es-module-lexer": "^1.6.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.4", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-OGX2KvPeBzjSSKhkCqrUoDMyzFcjKt5nTE5SFw3RdoLf0nrhyCXBQcCyclzWy1+P+XpOamn+p+hm1EhpCRyPxw=="],
|
||||
@@ -85,6 +92,8 @@
|
||||
|
||||
"@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=="],
|
||||
|
||||
"@astrojs/yaml2ts": ["@astrojs/yaml2ts@0.2.2", "", { "dependencies": { "yaml": "^2.5.0" } }, "sha512-GOfvSr5Nqy2z5XiwqTouBBpy5FyI6DEe+/g/Mk5am9SjILN1S5fOEvYK0GuWHg98yS/dobP4m8qyqw/URW35fQ=="],
|
||||
|
||||
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
|
||||
|
||||
"@babel/compat-data": ["@babel/compat-data@7.27.3", "", {}, "sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw=="],
|
||||
@@ -135,6 +144,20 @@
|
||||
|
||||
"@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="],
|
||||
|
||||
"@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="],
|
||||
|
||||
"@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="],
|
||||
|
||||
"@emmetio/css-parser": ["@emmetio/css-parser@0.4.0", "", { "dependencies": { "@emmetio/stream-reader": "^2.2.0", "@emmetio/stream-reader-utils": "^0.1.0" } }, "sha512-z7wkxRSZgrQHXVzObGkXG+Vmj3uRlpM11oCZ9pbaz0nFejvCDmAiNDpY75+wgXOcffKpj4rzGtwGaZxfJKsJxw=="],
|
||||
|
||||
"@emmetio/html-matcher": ["@emmetio/html-matcher@1.3.0", "", { "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ=="],
|
||||
|
||||
"@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="],
|
||||
|
||||
"@emmetio/stream-reader": ["@emmetio/stream-reader@2.2.0", "", {}, "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="],
|
||||
|
||||
"@emmetio/stream-reader-utils": ["@emmetio/stream-reader-utils@0.1.0", "", {}, "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="],
|
||||
@@ -247,6 +270,12 @@
|
||||
|
||||
"@mdx-js/mdx": ["@mdx-js/mdx@3.1.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@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=="],
|
||||
@@ -277,6 +306,8 @@
|
||||
|
||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
|
||||
|
||||
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collapsible": "1.1.11", "@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-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A=="],
|
||||
|
||||
"@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=="],
|
||||
@@ -525,12 +556,30 @@
|
||||
|
||||
"@vitest/utils": ["@vitest/utils@3.2.3", "", { "dependencies": { "@vitest/pretty-format": "3.2.3", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" } }, "sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q=="],
|
||||
|
||||
"@volar/kit": ["@volar/kit@2.4.14", "", { "dependencies": { "@volar/language-service": "2.4.14", "@volar/typescript": "2.4.14", "typesafe-path": "^0.2.2", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "typescript": "*" } }, "sha512-kBcmHjEodtmYGJELHePZd2JdeYm4ZGOd9F/pQ1YETYIzAwy4Z491EkJ1nRSo/GTxwKt0XYwYA/dHSEgXecVHRA=="],
|
||||
|
||||
"@volar/language-core": ["@volar/language-core@2.4.14", "", { "dependencies": { "@volar/source-map": "2.4.14" } }, "sha512-X6beusV0DvuVseaOEy7GoagS4rYHgDHnTrdOj5jeUb49fW5ceQyP9Ej5rBhqgz2wJggl+2fDbbojq1XKaxDi6w=="],
|
||||
|
||||
"@volar/language-server": ["@volar/language-server@2.4.14", "", { "dependencies": { "@volar/language-core": "2.4.14", "@volar/language-service": "2.4.14", "@volar/typescript": "2.4.14", "path-browserify": "^1.0.1", "request-light": "^0.7.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-P3mGbQbW0v40UYBnb3DAaNtRYx6/MGOVKzdOWmBCGwjUkCR2xBkGrCFt05XnPDwFS/cTWDh2U6Mc9lpZ8Aecfw=="],
|
||||
|
||||
"@volar/language-service": ["@volar/language-service@2.4.14", "", { "dependencies": { "@volar/language-core": "2.4.14", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-vNC3823EJohdzLTyjZoCMPwoWCfINB5emusniCkW5CGoGHQov4VVmT6yI5ncgP/NpgAIUv2NEkJooXvLHA4VeQ=="],
|
||||
|
||||
"@volar/source-map": ["@volar/source-map@2.4.14", "", {}, "sha512-5TeKKMh7Sfxo8021cJfmBzcjfY1SsXsPMMjMvjY7ivesdnybqqS+GxGAoXHAOUawQTwtdUxgP65Im+dEmvWtYQ=="],
|
||||
|
||||
"@volar/typescript": ["@volar/typescript@2.4.14", "", { "dependencies": { "@volar/language-core": "2.4.14", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-p8Z6f/bZM3/HyCdRNFZOEEzts51uV8WHeN8Tnfnm2EBv6FDB2TQLzfVx7aJvnl8ofKAOnS64B2O8bImBFaauRw=="],
|
||||
|
||||
"@vscode/emmet-helper": ["@vscode/emmet-helper@2.11.0", "", { "dependencies": { "emmet": "^2.4.3", "jsonc-parser": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.15.1", "vscode-uri": "^3.0.8" } }, "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw=="],
|
||||
|
||||
"@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="],
|
||||
|
||||
"acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="],
|
||||
|
||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||
|
||||
"agent-base": ["agent-base@7.1.3", "", {}, "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw=="],
|
||||
|
||||
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||
|
||||
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
@@ -569,6 +618,8 @@
|
||||
|
||||
"boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"brotli": ["brotli@1.3.3", "", { "dependencies": { "base64-js": "^1.1.2" } }, "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg=="],
|
||||
|
||||
"browserslist": ["browserslist@4.24.5", "", { "dependencies": { "caniuse-lite": "^1.0.30001716", "electron-to-chromium": "^1.5.149", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw=="],
|
||||
@@ -609,6 +660,8 @@
|
||||
|
||||
"cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
|
||||
|
||||
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||
|
||||
"clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
@@ -695,7 +748,9 @@
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.159", "", {}, "sha512-CEvHptWAMV5p6GJ0Lq8aheyvVbfzVrv5mmidu1D3pidoVNkB3tTBsTMVtPJ+rzRK5oV229mCLz9Zj/hNvU8GBA=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
"emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||
|
||||
@@ -743,8 +798,16 @@
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||
|
||||
"fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="],
|
||||
|
||||
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
||||
|
||||
"fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="],
|
||||
|
||||
"fontace": ["fontace@0.3.0", "", { "dependencies": { "@types/fontkit": "^2.0.8", "fontkit": "^2.0.4" } }, "sha512-czoqATrcnxgWb/nAkfyIrRp6Q8biYj7nGnL6zfhTcX+JKKpWHFBnb8uNMw/kZr7u++3Y3wYSYoZgHkCcsuBpBg=="],
|
||||
@@ -759,6 +822,8 @@
|
||||
|
||||
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="],
|
||||
|
||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||
@@ -767,6 +832,8 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
"globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
@@ -835,12 +902,18 @@
|
||||
|
||||
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
|
||||
|
||||
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
|
||||
|
||||
"is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="],
|
||||
@@ -857,8 +930,12 @@
|
||||
|
||||
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="],
|
||||
|
||||
"jsonwebtoken": ["jsonwebtoken@9.0.2", "", { "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="],
|
||||
|
||||
"jwa": ["jwa@1.4.2", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw=="],
|
||||
@@ -959,6 +1036,8 @@
|
||||
|
||||
"mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
|
||||
"micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
|
||||
|
||||
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
|
||||
@@ -1029,6 +1108,8 @@
|
||||
|
||||
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
|
||||
|
||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||
|
||||
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||
|
||||
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||
@@ -1045,6 +1126,8 @@
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
|
||||
@@ -1091,6 +1174,8 @@
|
||||
|
||||
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
|
||||
|
||||
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
|
||||
|
||||
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"pathval": ["pathval@2.0.0", "", {}, "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA=="],
|
||||
@@ -1101,6 +1186,8 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
|
||||
@@ -1111,6 +1198,8 @@
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
|
||||
|
||||
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
||||
@@ -1171,6 +1260,12 @@
|
||||
|
||||
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
|
||||
|
||||
"request-light": ["request-light@0.7.0", "", {}, "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="],
|
||||
|
||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||
|
||||
"restructure": ["restructure@3.0.2", "", {}, "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw=="],
|
||||
@@ -1183,10 +1278,14 @@
|
||||
|
||||
"retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="],
|
||||
|
||||
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
||||
|
||||
"rollup": ["rollup@4.41.1", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.41.1", "@rollup/rollup-android-arm64": "4.41.1", "@rollup/rollup-darwin-arm64": "4.41.1", "@rollup/rollup-darwin-x64": "4.41.1", "@rollup/rollup-freebsd-arm64": "4.41.1", "@rollup/rollup-freebsd-x64": "4.41.1", "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", "@rollup/rollup-linux-arm-musleabihf": "4.41.1", "@rollup/rollup-linux-arm64-gnu": "4.41.1", "@rollup/rollup-linux-arm64-musl": "4.41.1", "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-gnu": "4.41.1", "@rollup/rollup-linux-riscv64-musl": "4.41.1", "@rollup/rollup-linux-s390x-gnu": "4.41.1", "@rollup/rollup-linux-x64-gnu": "4.41.1", "@rollup/rollup-linux-x64-musl": "4.41.1", "@rollup/rollup-win32-arm64-msvc": "4.41.1", "@rollup/rollup-win32-ia32-msvc": "4.41.1", "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw=="],
|
||||
|
||||
"rrweb-cssom": ["rrweb-cssom@0.8.0", "", {}, "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
@@ -1229,11 +1328,11 @@
|
||||
|
||||
"std-env": ["std-env@3.9.0", "", {}, "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw=="],
|
||||
|
||||
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
"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=="],
|
||||
|
||||
"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@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
"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=="],
|
||||
|
||||
@@ -1273,6 +1372,8 @@
|
||||
|
||||
"tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||
|
||||
"tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="],
|
||||
@@ -1293,8 +1394,12 @@
|
||||
|
||||
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
||||
|
||||
"typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="],
|
||||
|
||||
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
|
||||
|
||||
"ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="],
|
||||
@@ -1359,6 +1464,40 @@
|
||||
|
||||
"vitest": ["vitest@3.2.3", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.3", "@vitest/mocker": "3.2.3", "@vitest/pretty-format": "^3.2.3", "@vitest/runner": "3.2.3", "@vitest/snapshot": "3.2.3", "@vitest/spy": "3.2.3", "@vitest/utils": "3.2.3", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.0", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.3", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.3", "@vitest/ui": "3.2.3", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-E6U2ZFXe3N/t4f5BwUaVCKRLHqUpk1CBWeMh78UT4VaTPH/2dyvH6ALl29JTovEPu9dVKr/K/J4PkXgrMbw4Ww=="],
|
||||
|
||||
"volar-service-css": ["volar-service-css@0.0.62", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-JwNyKsH3F8PuzZYuqPf+2e+4CTU8YoyUHEHVnoXNlrLe7wy9U3biomZ56llN69Ris7TTy/+DEX41yVxQpM4qvg=="],
|
||||
|
||||
"volar-service-emmet": ["volar-service-emmet@0.0.62", "", { "dependencies": { "@emmetio/css-parser": "^0.4.0", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-U4dxWDBWz7Pi4plpbXf4J4Z/ss6kBO3TYrACxWNsE29abu75QzVS0paxDDhI6bhqpbDFXlpsDhZ9aXVFpnfGRQ=="],
|
||||
|
||||
"volar-service-html": ["volar-service-html@0.0.62", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-Zw01aJsZRh4GTGUjveyfEzEqpULQUdQH79KNEiKVYHZyuGtdBRYCHlrus1sueSNMxwwkuF5WnOHfvBzafs8yyQ=="],
|
||||
|
||||
"volar-service-prettier": ["volar-service-prettier@0.0.62", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-h2yk1RqRTE+vkYZaI9KYuwpDfOQRrTEMvoHol0yW4GFKc75wWQRrb5n/5abDrzMPrkQbSip8JH2AXbvrRtYh4w=="],
|
||||
|
||||
"volar-service-typescript": ["volar-service-typescript@0.0.62", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.3", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-p7MPi71q7KOsH0eAbZwPBiKPp9B2+qrdHAd6VY5oTo9BUXatsOAdakTm9Yf0DUj6uWBAaOT01BSeVOPwucMV1g=="],
|
||||
|
||||
"volar-service-typescript-twoslash-queries": ["volar-service-typescript-twoslash-queries@0.0.62", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-KxFt4zydyJYYI0kFAcWPTh4u0Ha36TASPZkAnNY784GtgajerUqM80nX/W1d0wVhmcOFfAxkVsf/Ed+tiYU7ng=="],
|
||||
|
||||
"volar-service-yaml": ["volar-service-yaml@0.0.62", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.15.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-k7gvv7sk3wa+nGll3MaSKyjwQsJjIGCHFjVkl3wjaSP2nouKyn9aokGmqjrl39mi88Oy49giog2GkZH526wjig=="],
|
||||
|
||||
"vscode-css-languageservice": ["vscode-css-languageservice@6.3.6", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-fU4h8mT3KlvfRcbF74v/M+Gzbligav6QMx4AD/7CbclWPYOpGb9kgIswfpZVJbIcOEJJACI9iYizkNwdiAqlHw=="],
|
||||
|
||||
"vscode-html-languageservice": ["vscode-html-languageservice@5.5.0", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-No6Er2P2L8IsXDnUFlp0bP4f2sdkJv+zJLZYFhtEQIp+2xNfxY8WYkhSxLJ/7bZhuV/aU55lmGSSHBVxSGer3Q=="],
|
||||
|
||||
"vscode-json-languageservice": ["vscode-json-languageservice@4.1.8", "", { "dependencies": { "jsonc-parser": "^3.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2" } }, "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg=="],
|
||||
|
||||
"vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="],
|
||||
|
||||
"vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="],
|
||||
|
||||
"vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="],
|
||||
|
||||
"vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="],
|
||||
|
||||
"vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="],
|
||||
|
||||
"vscode-nls": ["vscode-nls@5.2.0", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="],
|
||||
|
||||
"vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
|
||||
|
||||
"w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="],
|
||||
|
||||
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
|
||||
@@ -1387,8 +1526,16 @@
|
||||
|
||||
"xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"yaml": ["yaml@2.8.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ=="],
|
||||
|
||||
"yaml-language-server": ["yaml-language-server@1.15.0", "", { "dependencies": { "ajv": "^8.11.0", "lodash": "4.17.21", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^7.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2", "yaml": "2.2.2" }, "optionalDependencies": { "prettier": "2.8.7" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-N47AqBDCMQmh6mBLmI6oqxryHRzi33aPFPsJhYy3VTUGCdLHYjGh4FZzpUjRlphaADBBkDmnkM/++KNIOHi5Rw=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="],
|
||||
@@ -1447,16 +1594,20 @@
|
||||
|
||||
"@types/babel__template/@babel/parser": ["@babel/parser@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw=="],
|
||||
|
||||
"ansi-align/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=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"boxen/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
||||
|
||||
"boxen/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="],
|
||||
|
||||
"magicast/@babel/parser": ["@babel/parser@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
@@ -1465,12 +1616,24 @@
|
||||
|
||||
"prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
|
||||
|
||||
"vscode-json-languageservice/jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="],
|
||||
|
||||
"widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||
|
||||
"wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
"yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
|
||||
|
||||
"yaml-language-server/vscode-languageserver": ["vscode-languageserver@7.0.0", "", { "dependencies": { "vscode-languageserver-protocol": "3.16.0" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw=="],
|
||||
|
||||
"yaml-language-server/yaml": ["yaml@2.2.2", "", {}, "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@babel/core": ["@babel/core@7.27.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.3", "@babel/parser": "^7.27.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.3", "@babel/types": "^7.27.3", "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-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.9", "", {}, "sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w=="],
|
||||
@@ -1481,14 +1644,24 @@
|
||||
|
||||
"@babel/helper-module-transforms/@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=="],
|
||||
|
||||
"ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
"boxen/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
|
||||
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
"boxen/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
"node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
"node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
|
||||
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"yaml-language-server/vscode-languageserver/vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.16.0", "", { "dependencies": { "vscode-jsonrpc": "6.0.0", "vscode-languageserver-types": "3.16.0" } }, "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@babel/core/@babel/helpers": ["@babel/helpers@7.27.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.27.3" } }, "sha512-h/eKy9agOya1IGuLaZ9tEUgz+uIRXcbtOhRtUyyMf8JFmn1iT13vnl/IGVWSkdOCG/pC57U4S1jnAabAavTMwg=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@babel/core/@babel/parser": ["@babel/parser@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw=="],
|
||||
@@ -1496,5 +1669,13 @@
|
||||
"@astrojs/react/@vitejs/plugin-react/@babel/core/@babel/traverse": ["@babel/traverse@7.27.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.27.3", "@babel/parser": "^7.27.3", "@babel/template": "^7.27.2", "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-lId/IfN/Ye1CIu8xG7oKBHXd2iNb2aW1ilPszzGcJug6M8RCKfVNcYhpI5+bMvFYjK7lXIM0R+a+6r8xhHp2FQ=="],
|
||||
|
||||
"@astrojs/react/@vitejs/plugin-react/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"boxen/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"widest-line/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"yaml-language-server/vscode-languageserver/vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@6.0.0", "", {}, "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg=="],
|
||||
|
||||
"yaml-language-server/vscode-languageserver/vscode-languageserver-protocol/vscode-languageserver-types": ["vscode-languageserver-types@3.16.0", "", {}, "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA=="],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ services:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
entrypoint: ["/tmp/gitea-dev-init.sh"]
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=sqlite3
|
||||
- GITEA__database__PATH=/data/gitea.db
|
||||
- GITEA__database__PATH=/data/gitea/gitea.db
|
||||
- GITEA__server__DOMAIN=localhost
|
||||
- GITEA__server__ROOT_URL=http://localhost:3001/
|
||||
- GITEA__server__SSH_DOMAIN=localhost
|
||||
@@ -19,20 +20,24 @@ services:
|
||||
- GITEA__server__START_SSH_SERVER=true
|
||||
- GITEA__security__INSTALL_LOCK=true
|
||||
- GITEA__service__DISABLE_REGISTRATION=false
|
||||
- GITEA__log__MODE=console
|
||||
- GITEA__log__LEVEL=Info
|
||||
ports:
|
||||
- "3001:3000"
|
||||
- "2222:22"
|
||||
volumes:
|
||||
- gitea-data:/data
|
||||
- gitea-config:/etc/gitea
|
||||
- ./scripts/gitea-app.ini:/tmp/app.ini:ro
|
||||
- ./scripts/gitea-dev-init.sh:/tmp/gitea-dev-init.sh:ro
|
||||
networks:
|
||||
- gitea-network
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/healthz"]
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
|
||||
# Development service connected to local Gitea
|
||||
gitea-mirror-dev:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "gitea-mirror",
|
||||
"type": "module",
|
||||
"version": "2.13.1",
|
||||
"version": "2.14.0",
|
||||
"engines": {
|
||||
"bun": ">=1.2.9"
|
||||
},
|
||||
@@ -31,10 +31,12 @@
|
||||
"astro": "bunx --bun astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/mdx": "^4.3.0",
|
||||
"@astrojs/node": "^9.2.2",
|
||||
"@astrojs/react": "^4.3.0",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
@@ -73,6 +75,7 @@
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "^4.1.10",
|
||||
"tw-animate-css": "^1.3.4",
|
||||
"typescript": "^5.8.3",
|
||||
"uuid": "^11.1.0",
|
||||
"zod": "^3.25.64"
|
||||
},
|
||||
|
||||
56
scripts/README-dev.md
Normal file
56
scripts/README-dev.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Development Environment Setup
|
||||
|
||||
This directory contains scripts to help set up a development environment with a pre-configured Gitea instance.
|
||||
|
||||
## Default Credentials
|
||||
|
||||
For development convenience, the Gitea instance is pre-configured with:
|
||||
|
||||
- **Admin Username**: `admin`
|
||||
- **Admin Password**: `admin123`
|
||||
- **Gitea URL**: http://localhost:3001
|
||||
|
||||
## Files
|
||||
|
||||
- `gitea-app.ini` - Pre-configured Gitea settings for development
|
||||
- `gitea-dev-init.sh` - Initialization script that copies the config on first run
|
||||
- `gitea-init.sql` - SQL script to create default admin user (not currently used)
|
||||
|
||||
## Usage
|
||||
|
||||
1. Start the development environment:
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml down
|
||||
docker volume rm gitea-mirror_gitea-data gitea-mirror_gitea-config
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
2. Wait for Gitea to start (check logs):
|
||||
```bash
|
||||
docker logs -f gitea
|
||||
```
|
||||
|
||||
3. Access Gitea at http://localhost:3001 and login with:
|
||||
- Username: `admin`
|
||||
- Password: `admin123`
|
||||
|
||||
4. Generate an API token:
|
||||
- Go to Settings → Applications
|
||||
- Generate New Token
|
||||
- Give it a name like "gitea-mirror"
|
||||
- Select all permissions (for development)
|
||||
- Copy the token
|
||||
|
||||
5. Configure gitea-mirror with the token in your `.env` file or through the web UI.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If Gitea doesn't start properly:
|
||||
|
||||
1. Check logs: `docker logs gitea`
|
||||
2. Ensure volumes are clean: `docker volume rm gitea-mirror_gitea-data gitea-mirror_gitea-config`
|
||||
3. Restart: `docker compose -f docker-compose.dev.yml up -d`
|
||||
|
||||
## Security Note
|
||||
|
||||
⚠️ **These credentials are for development only!** Never use these settings in production.
|
||||
@@ -1,43 +1,47 @@
|
||||
# LXC Container Deployment Guide
|
||||
|
||||
## Overview
|
||||
Run **Gitea Mirror** in an isolated LXC container, either:
|
||||
Run **Gitea Mirror** in an isolated LXC container:
|
||||
|
||||
1. **Online, on a Proxmox VE host** – script pulls everything from GitHub
|
||||
2. **Offline / LAN-only, on a developer laptop** – script pushes your local checkout + Bun ZIP
|
||||
1. **Proxmox VE (Recommended)** – Using the community-maintained script
|
||||
2. **Local Development** – Using the local LXC script for testing
|
||||
|
||||
---
|
||||
|
||||
## 1. Proxmox VE (online, recommended for prod)
|
||||
## 1. Proxmox VE Installation (Recommended)
|
||||
|
||||
### Prerequisites
|
||||
* Proxmox VE node with the default `vmbr0` bridge
|
||||
* Root shell on the node
|
||||
* Ubuntu 22.04 LXC template present (`pveam update && pveam download ...`)
|
||||
* Proxmox VE host with internet access
|
||||
* Root shell access on the Proxmox node
|
||||
|
||||
### One-command install
|
||||
|
||||
```bash
|
||||
# Community-maintained script for Proxmox VE by Tobias ([CrazyWolf13](https://github.com/CrazyWolf13))
|
||||
# at [community-scripts/ProxmoxVE](https://github.com/community-scripts/ProxmoxVE)
|
||||
# Official documentation: https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror
|
||||
# Community-maintained script from the Proxmox VE Community Scripts project
|
||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/gitea-mirror.sh)"
|
||||
```
|
||||
|
||||
What it does:
|
||||
### What the script does:
|
||||
|
||||
* Uses the community-maintained script from [Community Scripts for Proxmox VE](https://community-scripts.github.io/ProxmoxVE/)
|
||||
* Installs dependencies and Bun runtime
|
||||
* Clones & builds `arunavo4/gitea-mirror`
|
||||
* Creates a systemd service and starts it
|
||||
* Sets up a random `JWT_SECRET` for security
|
||||
* Creates a privileged Alpine Linux LXC container
|
||||
* Installs Bun runtime environment
|
||||
* Clones the Gitea Mirror repository
|
||||
* Builds the application
|
||||
* Configures a systemd service for automatic startup
|
||||
* Sets up the application to run on port 4321
|
||||
* Generates a secure `JWT_SECRET` automatically
|
||||
|
||||
Browse to:
|
||||
### Accessing Gitea Mirror:
|
||||
|
||||
```
|
||||
http://<container-ip>:4321
|
||||
```
|
||||
|
||||
### Additional Information:
|
||||
* **Script Source**: [Community Scripts for Proxmox VE](https://github.com/community-scripts/ProxmoxVE)
|
||||
* **Documentation**: [Gitea Mirror Script Documentation](https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror)
|
||||
* **Support**: [Community Scripts Discord](https://discord.gg/fiXVvSHnBU)
|
||||
|
||||
---
|
||||
|
||||
## 2. Local testing (LXD on a workstation, works offline)
|
||||
|
||||
68
scripts/gitea-app.ini
Normal file
68
scripts/gitea-app.ini
Normal file
@@ -0,0 +1,68 @@
|
||||
APP_NAME = Gitea: Git with a cup of tea
|
||||
RUN_MODE = prod
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /data/gitea/gitea.db
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
||||
[server]
|
||||
SSH_DOMAIN = localhost
|
||||
DOMAIN = localhost
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = http://localhost:3001/
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = _oaWNP5sCH5cSECa-K_HvCXeXhg-zN5H0cU5vVQAZr4
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = vLu5OuX0EweZjDNxKPQ5V9DXXXX8cJiKpJyQylKkMVTrNdFAzlUlNdYLYfiCybu
|
||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MjgzMTk1MDB9.Lz0cJB_DCLmJFh8FqDX0z9IUcxfY9jPftHEGvz_WeHo
|
||||
PASSWORD_HASH_ALGO = pbkdf2
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.localhost
|
||||
|
||||
[oauth2]
|
||||
JWT_SECRET = gQXt_D8B-VJGCvFfJ9xEj5yp8mOd6fAza8TKc9rJJYw
|
||||
|
||||
[lfs]
|
||||
PATH = /data/git/lfs
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = Info
|
||||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[repository.pull-request]
|
||||
DEFAULT_MERGE_STYLE = merge
|
||||
|
||||
[repository.signing]
|
||||
DEFAULT_TRUST_MODEL = committer
|
||||
|
||||
[actions]
|
||||
ENABLED = false
|
||||
14
scripts/gitea-create-admin.sh
Executable file
14
scripts/gitea-create-admin.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# Create admin user for Gitea development instance
|
||||
|
||||
echo "Creating admin user for Gitea..."
|
||||
docker exec -u git gitea gitea admin user create \
|
||||
--username admin \
|
||||
--password admin123 \
|
||||
--email admin@localhost \
|
||||
--admin \
|
||||
--must-change-password=false
|
||||
|
||||
echo "Admin user created!"
|
||||
echo "Username: admin"
|
||||
echo "Password: admin123"
|
||||
32
scripts/gitea-dev-init.sh
Executable file
32
scripts/gitea-dev-init.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
# Initialize Gitea for development with pre-configured settings
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p /data/gitea/conf
|
||||
|
||||
# Copy pre-configured app.ini if it doesn't exist
|
||||
if [ ! -f /data/gitea/conf/app.ini ]; then
|
||||
echo "Initializing Gitea with development configuration..."
|
||||
cp /tmp/app.ini /data/gitea/conf/app.ini
|
||||
chown 1000:1000 /data/gitea/conf/app.ini
|
||||
fi
|
||||
|
||||
# Start Gitea in background
|
||||
/usr/bin/entrypoint "$@" &
|
||||
GITEA_PID=$!
|
||||
|
||||
# Wait for Gitea to be ready
|
||||
echo "Waiting for Gitea to start..."
|
||||
until wget --no-verbose --tries=1 --spider http://localhost:3000/ 2>/dev/null; do
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Create admin user if it doesn't exist
|
||||
if [ ! -f /data/.admin_created ]; then
|
||||
echo "Creating default admin user..."
|
||||
su git -c "gitea admin user create --username admin --password admin123 --email admin@localhost --admin --must-change-password=false" && \
|
||||
touch /data/.admin_created
|
||||
fi
|
||||
|
||||
# Keep Gitea running in foreground
|
||||
wait $GITEA_PID
|
||||
@@ -1,123 +0,0 @@
|
||||
---
|
||||
title: "Architecture"
|
||||
description: "Comprehensive overview of the Gitea Mirror application architecture."
|
||||
order: 1
|
||||
updatedDate: 2025-05-22
|
||||
---
|
||||
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold text-foreground">Gitea Mirror Architecture</h1>
|
||||
<p class="text-muted-foreground mt-2">This document provides a comprehensive overview of the Gitea Mirror application architecture, including component diagrams, project structure, and detailed explanations of each part of the system.</p>
|
||||
</div>
|
||||
|
||||
## System Overview
|
||||
|
||||
<div class="mb-4">
|
||||
<p class="text-muted-foreground">Gitea Mirror is a web application that automates the mirroring of GitHub repositories to Gitea instances. It provides a user-friendly interface for configuring, monitoring, and managing mirroring operations without requiring users to edit configuration files or run Docker commands.</p>
|
||||
</div>
|
||||
|
||||
The application is built using:
|
||||
|
||||
- <span class="font-semibold text-foreground">Astro</span>: Web framework for the frontend
|
||||
- <span class="font-semibold text-foreground">React</span>: Component library for interactive UI elements
|
||||
- <span class="font-semibold text-foreground">Shadcn UI</span>: UI component library built on Tailwind CSS
|
||||
- <span class="font-semibold text-foreground">SQLite</span>: Database for storing configuration, state, and events
|
||||
- <span class="font-semibold text-foreground">Bun</span>: Runtime environment for the backend
|
||||
- <span class="font-semibold text-foreground">Drizzle ORM</span>: Type-safe ORM for database interactions
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Gitea Mirror"
|
||||
Frontend["Frontend<br/>(Astro + React)"]
|
||||
Backend["Backend<br/>(Bun)"]
|
||||
Database["Database<br/>(SQLite + Drizzle)"]
|
||||
|
||||
Frontend <--> Backend
|
||||
Backend <--> Database
|
||||
end
|
||||
|
||||
subgraph "External APIs"
|
||||
GitHub["GitHub API"]
|
||||
Gitea["Gitea API"]
|
||||
end
|
||||
|
||||
Backend --> GitHub
|
||||
Backend --> Gitea
|
||||
```
|
||||
|
||||
## Component Breakdown
|
||||
|
||||
### Frontend (Astro + React)
|
||||
|
||||
The frontend is built with Astro, a modern web framework that allows for server-side rendering and partial hydration. React components are used for interactive elements, providing a responsive and dynamic user interface.
|
||||
|
||||
Key frontend components:
|
||||
|
||||
- **Dashboard**: Overview of mirroring status and recent activity
|
||||
- **Repository Management**: Interface for managing repositories to mirror
|
||||
- **Organization Management**: Interface for managing GitHub organizations
|
||||
- **Configuration**: Settings for GitHub and Gitea connections
|
||||
- **Activity Log**: Detailed log of mirroring operations
|
||||
|
||||
### Backend (Bun)
|
||||
|
||||
The backend is built with Bun and provides API endpoints for the frontend to interact with. It handles:
|
||||
|
||||
- Authentication and user management
|
||||
- GitHub API integration
|
||||
- Gitea API integration
|
||||
- Mirroring operations
|
||||
- Database interactions
|
||||
|
||||
### Database (SQLite + Drizzle ORM)
|
||||
|
||||
SQLite with Bun's native SQLite driver is used for data persistence, with Drizzle ORM providing type-safe database interactions. The database stores:
|
||||
|
||||
- User accounts and authentication data
|
||||
- GitHub and Gitea configuration
|
||||
- Repository and organization information
|
||||
- Mirroring job history and status
|
||||
- Event notifications and their read status
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. **User Authentication**: Users authenticate through the frontend, which communicates with the backend to validate credentials.
|
||||
2. **Configuration**: Users configure GitHub and Gitea settings through the UI, which are stored in the SQLite database.
|
||||
3. **Repository Discovery**: The backend queries the GitHub API to discover repositories based on user configuration.
|
||||
4. **Mirroring Process**: When triggered, the backend fetches repository data from GitHub and pushes it to Gitea.
|
||||
5. **Status Tracking**: All operations are logged in the database and displayed in the Activity Log.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
gitea-mirror/
|
||||
├── src/ # Source code
|
||||
│ ├── components/ # React components
|
||||
│ ├── content/ # Documentation and content
|
||||
│ ├── layouts/ # Astro layout components
|
||||
│ ├── lib/ # Utility functions and database
|
||||
│ ├── pages/ # Astro pages and API routes
|
||||
│ └── styles/ # CSS and Tailwind styles
|
||||
├── public/ # Static assets
|
||||
├── data/ # Database and persistent data
|
||||
├── docker/ # Docker configuration
|
||||
└── scripts/ # Utility scripts for deployment and maintenance
|
||||
├── gitea-mirror-lxc-local.sh # Local LXC deployment script
|
||||
└── manage-db.ts # Database management tool
|
||||
```
|
||||
|
||||
## Deployment Options
|
||||
|
||||
Gitea Mirror supports multiple deployment options:
|
||||
|
||||
1. **Docker**: Run as a containerized application using Docker and docker-compose
|
||||
2. **LXC Containers**: Deploy in Linux Containers (LXC) on Proxmox VE (using community script by [Tobias/CrazyWolf13](https://github.com/CrazyWolf13)) or local workstations
|
||||
3. **Native**: Run directly on the host system using Bun runtime
|
||||
|
||||
Each deployment method has its own advantages:
|
||||
|
||||
- **Docker**: Isolation, easy updates, consistent environment
|
||||
- **LXC**: Lightweight virtualization, better performance than Docker, system-level isolation
|
||||
- **Native**: Best performance, direct access to system resources
|
||||
@@ -1,177 +0,0 @@
|
||||
---
|
||||
title: "Configuration"
|
||||
description: "Guide to configuring Gitea Mirror for your environment."
|
||||
order: 2
|
||||
updatedDate: 2025-05-22
|
||||
---
|
||||
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold text-foreground">Gitea Mirror Configuration Guide</h1>
|
||||
<p class="text-muted-foreground mt-2">This guide provides detailed information on how to configure Gitea Mirror for your environment.</p>
|
||||
</div>
|
||||
|
||||
## Configuration Methods
|
||||
|
||||
Gitea Mirror can be configured using:
|
||||
|
||||
1. <span class="font-semibold text-foreground">Environment Variables</span>: Set configuration options through environment variables
|
||||
2. <span class="font-semibold text-foreground">Web UI</span>: Configure the application through the web interface after installation
|
||||
|
||||
## Environment Variables
|
||||
|
||||
The following environment variables can be used to configure Gitea Mirror:
|
||||
|
||||
| Variable | Description | Default Value | Example |
|
||||
|----------|-------------|---------------|---------|
|
||||
| `NODE_ENV` | Runtime environment (development, production, test) | `development` | `production` |
|
||||
| `DATABASE_URL` | SQLite database URL | `file:data/gitea-mirror.db` | `file:path/to/your/database.db` |
|
||||
| `JWT_SECRET` | Secret key for JWT authentication | Auto-generated secure random string | `your-secure-random-string` |
|
||||
| `HOST` | Server host | `localhost` | `0.0.0.0` |
|
||||
| `PORT` | Server port | `4321` | `8080` |
|
||||
|
||||
### Important Security Note
|
||||
|
||||
The application will automatically generate a secure random `JWT_SECRET` on first run if one isn't provided or if the default value is used. This generated secret is stored in the data directory for persistence across container restarts.
|
||||
|
||||
While this auto-generation feature provides good security by default, you can still explicitly set your own `JWT_SECRET` for complete control over your deployment.
|
||||
|
||||
## Web UI Configuration
|
||||
|
||||
After installing and starting Gitea Mirror, you can configure it through the web interface:
|
||||
|
||||
1. Navigate to `http://your-server:port/`
|
||||
2. If this is your first time, you'll be guided through creating an admin account
|
||||
3. Log in with your credentials
|
||||
4. Go to the Configuration page
|
||||
|
||||
### GitHub Configuration
|
||||
|
||||
The GitHub configuration section allows you to connect to GitHub and specify which repositories to mirror.
|
||||
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| Username | Your GitHub username | - |
|
||||
| Token | GitHub personal access token | - |
|
||||
| Skip Forks | Skip forked repositories | `false` |
|
||||
| Private Repositories | Include private repositories | `false` |
|
||||
| Mirror Issues | Mirror issues from GitHub to Gitea | `false` |
|
||||
| Mirror Wiki | Mirror wiki pages from GitHub to Gitea | `false` |
|
||||
| Mirror Starred | Mirror starred repositories | `false` |
|
||||
| Mirror Organizations | Mirror organization repositories | `false` |
|
||||
| Only Mirror Orgs | Only mirror organization repositories | `false` |
|
||||
| Preserve Org Structure | Maintain organization structure in Gitea | `false` |
|
||||
| Skip Starred Issues | Skip mirroring issues for starred repositories | `false` |
|
||||
|
||||
#### GitHub Token Permissions
|
||||
|
||||
Your GitHub token needs the following permissions:
|
||||
|
||||
- `repo` - Full control of private repositories
|
||||
- `read:org` - Read organization membership
|
||||
- `read:user` - Read user profile data
|
||||
|
||||
To create a GitHub token:
|
||||
|
||||
1. Go to [GitHub Settings > Developer settings > Personal access tokens](https://github.com/settings/tokens)
|
||||
2. Click "Generate new token"
|
||||
3. Select the required permissions
|
||||
4. Copy the generated token and paste it into Gitea Mirror
|
||||
|
||||
### Gitea Configuration
|
||||
|
||||
The Gitea configuration section allows you to connect to your Gitea instance and specify how repositories should be mirrored.
|
||||
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| URL | Gitea server URL | - |
|
||||
| Token | Gitea access token | - |
|
||||
| Organization | Default organization for mirrored repositories | - |
|
||||
| Visibility | Default visibility for mirrored repositories | `public` |
|
||||
| Starred Repos Org | Organization for starred repositories | `github` |
|
||||
|
||||
#### Gitea Token Creation
|
||||
|
||||
To create a Gitea access token:
|
||||
|
||||
1. Log in to your Gitea instance
|
||||
2. Go to Settings > Applications
|
||||
3. Under "Generate New Token", enter a name for your token
|
||||
4. Click "Generate Token"
|
||||
5. Copy the generated token and paste it into Gitea Mirror
|
||||
|
||||
### Schedule Configuration
|
||||
|
||||
You can configure automatic mirroring on a schedule:
|
||||
|
||||
| Option | Description | Default |
|
||||
|--------|-------------|---------|
|
||||
| Enable Scheduling | Enable automatic mirroring | `false` |
|
||||
| Interval (seconds) | Time between mirroring operations | `3600` (1 hour) |
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Repository Filtering
|
||||
|
||||
You can include or exclude specific repositories using patterns:
|
||||
|
||||
- Include patterns: Only repositories matching these patterns will be mirrored
|
||||
- Exclude patterns: Repositories matching these patterns will be skipped
|
||||
|
||||
Example patterns:
|
||||
- `*` - All repositories
|
||||
- `org-name/*` - All repositories in a specific organization
|
||||
- `username/repo-name` - A specific repository
|
||||
|
||||
### Database Management
|
||||
|
||||
Gitea Mirror includes several database management tools that can be run from the command line:
|
||||
|
||||
```bash
|
||||
# Initialize the database (only if it doesn't exist)
|
||||
bun run init-db
|
||||
|
||||
# Check database status
|
||||
bun run check-db
|
||||
|
||||
# Fix database location issues
|
||||
bun run fix-db
|
||||
|
||||
# Reset all users (for testing signup flow)
|
||||
bun run reset-users
|
||||
|
||||
# Remove database files completely
|
||||
bun run cleanup-db
|
||||
```
|
||||
|
||||
### Event Management
|
||||
|
||||
Events in Gitea Mirror (such as repository mirroring operations) are stored in the SQLite database. You can manage these events using the following scripts:
|
||||
|
||||
```bash
|
||||
# View all events in the database
|
||||
bun scripts/check-events.ts
|
||||
|
||||
# Mark all events as read
|
||||
bun scripts/mark-events-read.ts
|
||||
```
|
||||
|
||||
For cleaning up old activities and events, use the cleanup button in the Activity Log page of the web interface.
|
||||
|
||||
### Health Check Endpoint
|
||||
|
||||
Gitea Mirror includes a built-in health check endpoint at `/api/health` that provides:
|
||||
|
||||
- System status and uptime
|
||||
- Database connectivity check
|
||||
- Memory usage statistics
|
||||
- Environment information
|
||||
|
||||
You can use this endpoint for monitoring your deployment:
|
||||
|
||||
```bash
|
||||
# Basic check (returns 200 OK if healthy)
|
||||
curl -I http://your-server:port/api/health
|
||||
|
||||
# Detailed health information (JSON)
|
||||
curl http://your-server:port/api/health
|
||||
```
|
||||
@@ -1,182 +0,0 @@
|
||||
---
|
||||
title: "Quick Start Guide"
|
||||
description: "Get started with Gitea Mirror quickly."
|
||||
order: 3
|
||||
updatedDate: 2025-05-22
|
||||
---
|
||||
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl font-bold text-foreground">Gitea Mirror Quick Start Guide</h1>
|
||||
<p class="text-muted-foreground mt-2">This guide will help you get Gitea Mirror up and running quickly.</p>
|
||||
</div>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, make sure you have:
|
||||
|
||||
1. <span class="font-semibold text-foreground">A GitHub account with a personal access token</span>
|
||||
2. <span class="font-semibold text-foreground">A Gitea instance with an access token</span>
|
||||
3. <span class="font-semibold text-foreground">One of the following:</span>
|
||||
- Docker and docker-compose (for Docker deployment)
|
||||
- Bun 1.2.9+ (for native deployment)
|
||||
- Proxmox VE or LXD (for LXC container deployment)
|
||||
|
||||
## Installation Options
|
||||
|
||||
Choose the installation method that works best for your environment.
|
||||
|
||||
### Using Docker (Recommended for most users)
|
||||
|
||||
Docker provides the easiest way to get started with minimal configuration.
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/arunavo4/gitea-mirror.git
|
||||
cd gitea-mirror
|
||||
```
|
||||
|
||||
2. Start the application in production mode:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
3. Access the application at [http://localhost:4321](http://localhost:4321)
|
||||
|
||||
### Using Bun (Native Installation)
|
||||
|
||||
If you prefer to run the application directly on your system:
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/arunavo4/gitea-mirror.git
|
||||
cd gitea-mirror
|
||||
```
|
||||
|
||||
2. Run the quick setup script:
|
||||
```bash
|
||||
bun run setup
|
||||
```
|
||||
This installs dependencies and initializes the database.
|
||||
|
||||
3. Choose how to run the application:
|
||||
|
||||
**Development Mode:**
|
||||
```bash
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Note: For Bun-specific features, use:
|
||||
```bash
|
||||
bunx --bun astro dev
|
||||
```
|
||||
|
||||
**Production Mode:**
|
||||
```bash
|
||||
bun run build
|
||||
bun run start
|
||||
```
|
||||
|
||||
4. Access the application at [http://localhost:4321](http://localhost:4321)
|
||||
|
||||
### Using LXC Containers (Recommended for server deployments)
|
||||
|
||||
#### Proxmox VE (Online Installation)
|
||||
|
||||
For deploying on a Proxmox VE host with internet access:
|
||||
|
||||
```bash
|
||||
# Optional env overrides: CTID HOSTNAME STORAGE DISK_SIZE CORES MEMORY BRIDGE IP_CONF
|
||||
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-proxmox.sh)"
|
||||
```
|
||||
|
||||
This script:
|
||||
- Creates a privileged LXC container
|
||||
- Installs Bun and dependencies
|
||||
- Clones and builds the application
|
||||
- Sets up a systemd service
|
||||
|
||||
#### Local LXD (Offline-friendly Installation)
|
||||
|
||||
For testing on a local workstation or in environments without internet access:
|
||||
|
||||
1. Clone the repository locally:
|
||||
```bash
|
||||
git clone https://github.com/arunavo4/gitea-mirror.git
|
||||
```
|
||||
|
||||
2. Download the Bun installer once:
|
||||
```bash
|
||||
curl -L -o /tmp/bun-linux-x64.zip https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip
|
||||
```
|
||||
|
||||
3. Run the local LXC installer:
|
||||
```bash
|
||||
sudo LOCAL_REPO_DIR=~/path/to/gitea-mirror ./gitea-mirror/scripts/gitea-mirror-lxc-local.sh
|
||||
```
|
||||
|
||||
For more details on LXC deployment, see the [LXC Container Deployment Guide](https://github.com/arunavo4/gitea-mirror/blob/main/scripts/README-lxc.md).
|
||||
|
||||
## Initial Configuration
|
||||
|
||||
Follow these steps to configure Gitea Mirror for first use:
|
||||
|
||||
1. **Create Admin Account**
|
||||
- Upon first access, you'll be prompted to create an admin account
|
||||
- Choose a secure username and password
|
||||
- This will be your administrator account
|
||||
|
||||
2. **Configure GitHub Connection**
|
||||
- Navigate to the Configuration page
|
||||
- Enter your GitHub username
|
||||
- Enter your GitHub personal access token
|
||||
- Select which repositories to mirror (all, starred, organizations)
|
||||
- Configure repository filtering options
|
||||
|
||||
3. **Configure Gitea Connection**
|
||||
- Enter your Gitea server URL
|
||||
- Enter your Gitea access token
|
||||
- Configure organization and visibility settings
|
||||
|
||||
4. **Set Up Scheduling (Optional)**
|
||||
- Enable automatic mirroring if desired
|
||||
- Set the mirroring interval (in seconds)
|
||||
|
||||
5. **Save Configuration**
|
||||
- Click the "Save" button to store your settings
|
||||
|
||||
## Performing Your First Mirror
|
||||
|
||||
After completing the configuration, you can start mirroring repositories:
|
||||
|
||||
1. Click "Import GitHub Data" to fetch repositories from GitHub
|
||||
2. Go to the Repositories page to view your imported repositories
|
||||
3. Select the repositories you want to mirror
|
||||
4. Click "Mirror Selected" to start the mirroring process
|
||||
5. Monitor the progress on the Activity page
|
||||
6. You'll receive toast notifications about the success or failure of operations
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter any issues:
|
||||
|
||||
- Check the Activity Log for detailed error messages
|
||||
- Verify your GitHub and Gitea tokens have the correct permissions
|
||||
- Ensure your Gitea instance is accessible from the machine running Gitea Mirror
|
||||
- Check logs based on your deployment method:
|
||||
- Docker: `docker logs gitea-mirror`
|
||||
- Native: Check the terminal output or system logs
|
||||
- LXC: `systemctl status gitea-mirror` or `journalctl -u gitea-mirror -f`
|
||||
- Use the health check endpoint to verify system status: `curl http://your-server:4321/api/health`
|
||||
- For database issues, try the database management tools: `bun run check-db` or `bun run fix-db`
|
||||
|
||||
## Next Steps
|
||||
|
||||
After your initial setup:
|
||||
|
||||
- Explore the dashboard for an overview of your mirroring status
|
||||
- Set up automatic mirroring schedules for hands-off operation
|
||||
- Configure organization mirroring for team repositories
|
||||
- Check out the [Configuration Guide](/configuration) for advanced settings
|
||||
- Review the [Architecture Documentation](/architecture) to understand the system
|
||||
- For server deployments, set up monitoring using the health check endpoint
|
||||
- Use the cleanup button in the Activity Log page to manage old events and activities
|
||||
@@ -26,13 +26,39 @@ export const getGiteaRepoOwner = ({
|
||||
throw new Error("Gitea username is required.");
|
||||
}
|
||||
|
||||
// if the config has preserveOrgStructure set to true, then use the org name as the owner
|
||||
if (config.githubConfig.preserveOrgStructure && repository.organization) {
|
||||
return repository.organization;
|
||||
// Check if repository is starred - starred repos always go to starredReposOrg
|
||||
if (repository.isStarred && config.giteaConfig.starredReposOrg) {
|
||||
return config.giteaConfig.starredReposOrg;
|
||||
}
|
||||
|
||||
// if the config has preserveOrgStructure set to false, then use the gitea username as the owner
|
||||
return config.giteaConfig.username;
|
||||
// Get the mirror strategy - use preserveOrgStructure for backward compatibility
|
||||
const mirrorStrategy = config.giteaConfig.mirrorStrategy ||
|
||||
(config.githubConfig.preserveOrgStructure ? "preserve" : "flat-user");
|
||||
|
||||
switch (mirrorStrategy) {
|
||||
case "preserve":
|
||||
// Keep GitHub structure - org repos go to same org, personal repos to user
|
||||
if (repository.organization) {
|
||||
return repository.organization;
|
||||
}
|
||||
return config.giteaConfig.username;
|
||||
|
||||
case "single-org":
|
||||
// All non-starred repos go to the destination organization
|
||||
if (config.giteaConfig.organization) {
|
||||
return config.giteaConfig.organization;
|
||||
}
|
||||
// Fallback to username if no organization specified
|
||||
return config.giteaConfig.username;
|
||||
|
||||
case "flat-user":
|
||||
// All non-starred repos go under the user account
|
||||
return config.giteaConfig.username;
|
||||
|
||||
default:
|
||||
// Default fallback
|
||||
return config.giteaConfig.username;
|
||||
}
|
||||
};
|
||||
|
||||
export const isRepoPresentInGitea = async ({
|
||||
|
||||
@@ -6,6 +6,7 @@ import { repositoryVisibilityEnum, repoStatusEnum } from "@/types/Repository";
|
||||
import {
|
||||
mirrorGithubRepoToGitea,
|
||||
mirrorGitHubOrgRepoToGiteaOrg,
|
||||
getGiteaRepoOwner,
|
||||
} from "@/lib/gitea";
|
||||
import { createGitHubClient } from "@/lib/github";
|
||||
import { processWithResilience } from "@/lib/utils/concurrency";
|
||||
@@ -96,12 +97,20 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
// Log the start of mirroring
|
||||
console.log(`Starting mirror for repository: ${repo.name}`);
|
||||
|
||||
// Mirror the repository based on whether it's in an organization
|
||||
if (repo.organization && config.githubConfig.preserveOrgStructure) {
|
||||
// Determine where the repository should be mirrored
|
||||
const owner = getGiteaRepoOwner({
|
||||
config,
|
||||
repository: repoData,
|
||||
});
|
||||
|
||||
console.log(`Repository ${repo.name} will be mirrored to owner: ${owner}`);
|
||||
|
||||
// Check if owner is different from the user (means it's going to an org)
|
||||
if (owner !== config.giteaConfig?.username) {
|
||||
await mirrorGitHubOrgRepoToGiteaOrg({
|
||||
config,
|
||||
octokit,
|
||||
orgName: repo.organization,
|
||||
orgName: owner,
|
||||
repository: repoData,
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -93,6 +93,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
lastMirrored: repo.lastMirrored ?? undefined,
|
||||
errorMessage: repo.errorMessage ?? undefined,
|
||||
forkedFrom: repo.forkedFrom ?? undefined,
|
||||
mirroredLocation: repo.mirroredLocation || "",
|
||||
};
|
||||
|
||||
// Log the start of retry operation
|
||||
@@ -134,13 +135,14 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
throw new Error("Octokit client is not initialized.");
|
||||
}
|
||||
|
||||
console.log(`Importing repo: ${repo.name} ${owner}`);
|
||||
console.log(`Importing repo: ${repo.name} to owner: ${owner}`);
|
||||
|
||||
if (repo.organization && config.githubConfig.preserveOrgStructure) {
|
||||
// Check if owner is different from the user (means it's going to an org)
|
||||
if (owner !== config.giteaConfig?.username) {
|
||||
await mirrorGitHubOrgRepoToGiteaOrg({
|
||||
config,
|
||||
octokit,
|
||||
orgName: repo.organization,
|
||||
orgName: owner,
|
||||
repository: {
|
||||
...repoData,
|
||||
status: repoStatusEnum.parse("imported"),
|
||||
|
||||
@@ -112,6 +112,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
organization: repo.organization ?? undefined,
|
||||
lastMirrored: repo.lastMirrored ?? undefined,
|
||||
errorMessage: repo.errorMessage ?? undefined,
|
||||
mirroredLocation: repo.mirroredLocation || "",
|
||||
forkedFrom: repo.forkedFrom ?? undefined,
|
||||
visibility: repositoryVisibilityEnum.parse(repo.visibility),
|
||||
},
|
||||
@@ -133,6 +134,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
errorMessage: repo.errorMessage ?? undefined,
|
||||
forkedFrom: repo.forkedFrom ?? undefined,
|
||||
visibility: repositoryVisibilityEnum.parse(repo.visibility),
|
||||
mirroredLocation: repo.mirroredLocation || "",
|
||||
})),
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { repositoryVisibilityEnum, repoStatusEnum } from "@/types/Repository";
|
||||
import { syncGiteaRepo } from "@/lib/gitea";
|
||||
import type { SyncRepoResponse } from "@/types/sync";
|
||||
import { processWithResilience } from "@/lib/utils/concurrency";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { createSecureErrorResponse } from "@/lib/utils";
|
||||
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
@@ -68,9 +67,6 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
// Define the concurrency limit - adjust based on API rate limits
|
||||
const CONCURRENCY_LIMIT = 5;
|
||||
|
||||
// Generate a batch ID to group related repositories
|
||||
const batchId = uuidv4();
|
||||
|
||||
// Process repositories in parallel with resilience to container restarts
|
||||
await processWithResilience(
|
||||
repos,
|
||||
@@ -84,6 +80,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
errorMessage: repo.errorMessage ?? undefined,
|
||||
forkedFrom: repo.forkedFrom ?? undefined,
|
||||
visibility: repositoryVisibilityEnum.parse(repo.visibility),
|
||||
mirroredLocation: repo.mirroredLocation || "",
|
||||
};
|
||||
|
||||
// Log the start of syncing
|
||||
@@ -100,7 +97,6 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
{
|
||||
userId: config.userId || "",
|
||||
jobType: "sync",
|
||||
batchId,
|
||||
getItemId: (repo) => repo.id,
|
||||
getItemName: (repo) => repo.name,
|
||||
concurrencyLimit: CONCURRENCY_LIMIT,
|
||||
@@ -135,6 +131,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
errorMessage: repo.errorMessage ?? undefined,
|
||||
forkedFrom: repo.forkedFrom ?? undefined,
|
||||
visibility: repositoryVisibilityEnum.parse(repo.visibility),
|
||||
mirroredLocation: repo.mirroredLocation || "",
|
||||
})),
|
||||
};
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
status: "imported" as Repository["status"],
|
||||
lastMirrored: undefined,
|
||||
errorMessage: undefined,
|
||||
mirroredLocation: "",
|
||||
createdAt: repoData.created_at
|
||||
? new Date(repoData.created_at)
|
||||
: new Date(),
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import MainLayout from '../../layouts/main.astro';
|
||||
|
||||
// Enable prerendering for this dynamic route
|
||||
export const prerender = true;
|
||||
|
||||
// Generate static paths for all documentation pages
|
||||
export async function getStaticPaths() {
|
||||
const docs = await getCollection('docs');
|
||||
return docs.map(entry => ({
|
||||
params: { slug: entry.slug },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
// Get the documentation entry from props
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await entry.render();
|
||||
---
|
||||
|
||||
<MainLayout title={entry.data.title}>
|
||||
<main class="max-w-5xl mx-auto px-4 py-12">
|
||||
<div class="sticky top-4 z-10 mb-6">
|
||||
<a
|
||||
href="/docs/"
|
||||
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-card text-foreground hover:bg-muted transition-colors border border-border focus:ring-2 focus:ring-ring outline-none"
|
||||
>
|
||||
<span aria-hidden="true">←</span> Back to Documentation
|
||||
</a>
|
||||
</div>
|
||||
<article class="bg-card rounded-2xl shadow-lg p-6 border border-border">
|
||||
<div class="prose prose-neutral dark:prose-invert prose-code:bg-muted prose-code:text-foreground prose-pre:bg-muted prose-pre:text-foreground prose-pre:rounded-lg prose-pre:p-4 prose-table:rounded-lg prose-table:bg-muted prose-th:text-foreground prose-td:text-muted-foreground prose-blockquote:border-l-4 prose-blockquote:border-muted prose-blockquote:bg-muted/50 prose-blockquote:p-4">
|
||||
<Content />
|
||||
</div>
|
||||
</article>
|
||||
<script type="module">
|
||||
// Mermaid diagram rendering for code blocks
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
mermaid.initialize({ startOnLoad: false, theme: document.documentElement.classList.contains('dark') ? 'dark' : 'default' });
|
||||
function renderMermaidDiagrams() {
|
||||
document.querySelectorAll('pre code.language-mermaid').forEach((block, i) => {
|
||||
const parent = block.parentElement;
|
||||
if (!parent) return;
|
||||
const code = block.textContent;
|
||||
const id = `mermaid-diagram-${i}`;
|
||||
const container = document.createElement('div');
|
||||
container.className = 'my-6';
|
||||
container.id = id;
|
||||
parent.replaceWith(container);
|
||||
mermaid.render(id, code, (svgCode) => {
|
||||
container.innerHTML = svgCode;
|
||||
});
|
||||
});
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', renderMermaidDiagrams);
|
||||
} else {
|
||||
renderMermaidDiagrams();
|
||||
}
|
||||
</script>
|
||||
</main>
|
||||
</MainLayout>
|
||||
335
src/pages/docs/architecture.astro
Normal file
335
src/pages/docs/architecture.astro
Normal file
@@ -0,0 +1,335 @@
|
||||
---
|
||||
import MainLayout from '../../layouts/main.astro';
|
||||
---
|
||||
|
||||
<MainLayout title="Architecture - Gitea Mirror">
|
||||
<main class="max-w-5xl mx-auto px-4 py-12">
|
||||
<div class="sticky top-4 z-10 mb-6">
|
||||
<a
|
||||
href="/docs/"
|
||||
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-card text-foreground hover:bg-muted transition-colors border border-border focus:ring-2 focus:ring-ring outline-none"
|
||||
>
|
||||
<span aria-hidden="true">←</span> Back to Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<article class="bg-card rounded-2xl shadow-lg p-6 md:p-8 border border-border">
|
||||
<!-- Header -->
|
||||
<div class="mb-12 space-y-4">
|
||||
<div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-1 4h1m-1 4h1"/>
|
||||
</svg>
|
||||
<span>Architecture Overview</span>
|
||||
</div>
|
||||
<h1 class="text-4xl font-bold tracking-tight">Gitea Mirror Architecture</h1>
|
||||
<p class="text-lg text-muted-foreground leading-relaxed max-w-4xl">
|
||||
This document provides a comprehensive overview of the Gitea Mirror application architecture, including component diagrams, project structure, and detailed explanations of each part of the system.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- System Overview -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">System Overview</h2>
|
||||
|
||||
<div class="bg-card/50 border border-border/50 rounded-lg p-6 mb-8">
|
||||
<p class="text-base leading-relaxed mb-6">
|
||||
Gitea Mirror is a web application that automates the mirroring of GitHub repositories to Gitea instances. It provides a user-friendly interface for configuring, monitoring, and managing mirroring operations without requiring users to edit configuration files or run Docker commands.
|
||||
</p>
|
||||
|
||||
<div class="space-y-1">
|
||||
<h3 class="text-sm font-semibold text-muted-foreground uppercase tracking-wider mb-3">Technology Stack</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{[
|
||||
{ name: 'Astro', desc: 'Web framework for Server-Side Rendering (SSR)' },
|
||||
{ name: 'React', desc: 'Component library for interactive UI elements' },
|
||||
{ name: 'Tailwind CSS v4', desc: 'Utility-first CSS framework (with Vite plugin)' },
|
||||
{ name: 'Shadcn UI', desc: 'UI component library built on Tailwind CSS' },
|
||||
{ name: 'SQLite', desc: 'Database for storing configuration, state, and events' },
|
||||
{ name: 'Bun', desc: 'JavaScript runtime and package manager' },
|
||||
{ name: 'Drizzle ORM', desc: 'Type-safe ORM for database interactions' }
|
||||
].map(tech => (
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-2 h-2 rounded-full bg-primary mt-2"></div>
|
||||
<div>
|
||||
<span class="font-semibold text-foreground">{tech.name}</span>
|
||||
<p class="text-sm text-muted-foreground">{tech.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Architecture Diagram -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Architecture Diagram</h2>
|
||||
|
||||
<div class="my-8">
|
||||
<div class="architecture-diagram bg-muted/30 rounded-xl p-8 border border-border">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<!-- Gitea Mirror System -->
|
||||
<div class="bg-card rounded-lg border-2 border-primary/20 p-6">
|
||||
<h3 class="text-lg font-semibold mb-6 text-center text-primary">Gitea Mirror System</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
{[
|
||||
{ icon: '🎨', name: 'Frontend', tech: 'Astro + React' },
|
||||
{ icon: '⚙️', name: 'Backend', tech: 'Bun Runtime' },
|
||||
{ icon: '🗄️', name: 'Database', tech: 'SQLite + Drizzle' }
|
||||
].map((component, index) => (
|
||||
<>
|
||||
<div class="bg-primary/10 rounded-lg p-4 text-center">
|
||||
<div class="text-2xl mb-2">{component.icon}</div>
|
||||
<h4 class="font-semibold">{component.name}</h4>
|
||||
<p class="text-sm text-muted-foreground mt-1">{component.tech}</p>
|
||||
</div>
|
||||
{index < 2 && (
|
||||
<div class="flex justify-center">
|
||||
<div class="text-muted-foreground">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- External APIs -->
|
||||
<div class="space-y-4">
|
||||
<div class="bg-card rounded-lg border-2 border-amber-500/20 p-6">
|
||||
<h3 class="text-lg font-semibold mb-6 text-center text-amber-600 dark:text-amber-500">External APIs</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="bg-amber-500/10 rounded-lg p-4 text-center">
|
||||
<div class="text-2xl mb-2">🐙</div>
|
||||
<h4 class="font-semibold">GitHub API</h4>
|
||||
<p class="text-sm text-muted-foreground mt-1">Repository Data Source</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-amber-500/10 rounded-lg p-4 text-center">
|
||||
<div class="text-2xl mb-2">🍵</div>
|
||||
<h4 class="font-semibold">Gitea API</h4>
|
||||
<p class="text-sm text-muted-foreground mt-1">Mirror Destination</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-center gap-4 mt-6">
|
||||
<div class="text-center">
|
||||
<div class="text-sm text-muted-foreground mb-2">Data Flow</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-primary font-semibold">Backend</span>
|
||||
<svg class="w-6 h-6 text-muted-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
|
||||
</svg>
|
||||
<span class="text-amber-600 dark:text-amber-500 font-semibold">APIs</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Component Breakdown -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Component Breakdown</h2>
|
||||
|
||||
<!-- Frontend -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">Frontend (Astro + React)</h3>
|
||||
<div class="pl-4 border-l-2 border-primary/20">
|
||||
<p class="text-muted-foreground mb-4">
|
||||
The frontend is built with Astro, a modern web framework that allows for server-side rendering and partial hydration. React components are used for interactive elements, providing a responsive and dynamic user interface.
|
||||
</p>
|
||||
|
||||
<h4 class="font-semibold mb-3">Key Frontend Components</h4>
|
||||
<div class="space-y-3">
|
||||
{[
|
||||
{ name: 'Dashboard', desc: 'Overview of mirroring status and recent activity' },
|
||||
{ name: 'Repository Management', desc: 'Interface for managing repositories to mirror' },
|
||||
{ name: 'Organization Management', desc: 'Interface for managing GitHub organizations' },
|
||||
{ name: 'Configuration', desc: 'Settings for GitHub and Gitea connections' },
|
||||
{ name: 'Activity Log', desc: 'Detailed log of mirroring operations' }
|
||||
].map(component => (
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary font-mono text-sm">▸</span>
|
||||
<div>
|
||||
<strong>{component.name}</strong>
|
||||
<p class="text-sm text-muted-foreground mt-1">{component.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Backend -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">Backend (Bun)</h3>
|
||||
<div class="pl-4 border-l-2 border-primary/20">
|
||||
<p class="text-muted-foreground mb-4">
|
||||
The backend is built with Bun and provides API endpoints for the frontend to interact with. It handles:
|
||||
</p>
|
||||
|
||||
<div class="space-y-3">
|
||||
{[
|
||||
'Authentication and user management',
|
||||
'GitHub API integration',
|
||||
'Gitea API integration',
|
||||
'Mirroring operations and job queue',
|
||||
'Real-time updates via Server-Sent Events (SSE) at /api/sse/',
|
||||
'Job recovery system for interrupted operations',
|
||||
'Graceful shutdown handling',
|
||||
'Scheduled automatic mirroring',
|
||||
'Database interactions with Drizzle ORM'
|
||||
].map(item => (
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary font-mono text-sm">▸</span>
|
||||
<span>{item}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Database -->
|
||||
<div>
|
||||
<h3 class="text-xl font-semibold mb-4">Database (SQLite + Drizzle ORM)</h3>
|
||||
<div class="pl-4 border-l-2 border-primary/20">
|
||||
<p class="text-muted-foreground mb-4">
|
||||
SQLite with Bun's native SQLite driver is used for data persistence, with Drizzle ORM providing type-safe database interactions. The database stores:
|
||||
</p>
|
||||
|
||||
<div class="space-y-3">
|
||||
{[
|
||||
'User accounts and authentication data',
|
||||
'GitHub and Gitea configuration',
|
||||
'Repository and organization information',
|
||||
'Mirroring job history and status',
|
||||
'Event notifications and their read status'
|
||||
].map(item => (
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary font-mono text-sm">▸</span>
|
||||
<span>{item}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Data Flow -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Data Flow</h2>
|
||||
|
||||
<div class="bg-gradient-to-r from-primary/5 to-transparent rounded-lg p-6 border-l-4 border-primary">
|
||||
<ol class="space-y-4">
|
||||
{[
|
||||
{ title: 'User Authentication', desc: 'Users authenticate through the frontend, which communicates with the backend to validate credentials.' },
|
||||
{ title: 'Configuration', desc: 'Users configure GitHub and Gitea settings through the UI, which are stored in the SQLite database.' },
|
||||
{ title: 'Repository Discovery', desc: 'The backend queries the GitHub API to discover repositories based on user configuration.' },
|
||||
{ title: 'Mirroring Process', desc: 'When triggered, the backend fetches repository data from GitHub and pushes it to Gitea.' },
|
||||
{ title: 'Status Tracking', desc: 'All operations are logged in the database and displayed in the Activity Log.' }
|
||||
].map((step, index) => (
|
||||
<li class="flex gap-4">
|
||||
<span class="flex-shrink-0 w-8 h-8 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">
|
||||
{index + 1}
|
||||
</span>
|
||||
<div>
|
||||
<strong class="text-foreground">{step.title}</strong>
|
||||
<p class="text-sm text-muted-foreground mt-1">{step.desc}</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Project Structure -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Project Structure</h2>
|
||||
|
||||
<div class="bg-muted/30 rounded-lg p-4">
|
||||
<pre class="text-sm"><code>{`gitea-mirror/
|
||||
├── src/ # Source code
|
||||
│ ├── components/ # React components
|
||||
│ ├── content/ # Documentation and content
|
||||
│ ├── layouts/ # Astro layout components
|
||||
│ ├── lib/ # Utility functions and database
|
||||
│ ├── pages/ # Astro pages and API routes
|
||||
│ └── styles/ # CSS and Tailwind styles
|
||||
├── public/ # Static assets
|
||||
├── data/ # Database and persistent data
|
||||
├── docker/ # Docker configuration
|
||||
└── scripts/ # Utility scripts for deployment and maintenance
|
||||
├── gitea-mirror-lxc-local.sh # Local LXC deployment script
|
||||
└── manage-db.ts # Database management tool`}</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Deployment Options -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold mb-6">Deployment Options</h2>
|
||||
|
||||
<p class="text-muted-foreground mb-6">Gitea Mirror supports multiple deployment options:</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-6">
|
||||
{[
|
||||
{ icon: '🐳', name: 'Docker', desc: 'Run as a containerized application using Docker and docker-compose' },
|
||||
{ icon: '📦', name: 'LXC Containers', desc: 'Deploy in Linux Containers on Proxmox VE using community script' },
|
||||
{ icon: '🏃', name: 'Native', desc: 'Run directly on the host system using Bun runtime' }
|
||||
].map(option => (
|
||||
<div class="bg-card rounded-lg border border-border p-4 hover:border-primary/50 transition-colors">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="text-2xl">{option.icon}</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-1">{option.name}</h4>
|
||||
<p class="text-sm text-muted-foreground">{option.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="bg-muted/30 rounded-lg p-4 mt-6">
|
||||
<h4 class="font-semibold mb-3">Deployment Advantages</h4>
|
||||
<div class="space-y-2">
|
||||
<div class="flex gap-3">
|
||||
<strong class="text-primary">Docker:</strong>
|
||||
<span class="text-muted-foreground">Isolation, easy updates, consistent environment</span>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<strong class="text-primary">LXC:</strong>
|
||||
<span class="text-muted-foreground">Lightweight virtualization, better performance than Docker, system-level isolation</span>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<strong class="text-primary">Native:</strong>
|
||||
<span class="text-muted-foreground">Best performance, direct access to system resources</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-sm text-muted-foreground">
|
||||
<p><strong>Note:</strong> LXC deployment is available through the <a href="https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror" class="text-primary hover:underline">Proxmox VE Community Scripts</a> project.</p>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
</MainLayout>
|
||||
512
src/pages/docs/configuration.astro
Normal file
512
src/pages/docs/configuration.astro
Normal file
@@ -0,0 +1,512 @@
|
||||
---
|
||||
import MainLayout from '../../layouts/main.astro';
|
||||
|
||||
const envVars = [
|
||||
{ name: 'NODE_ENV', desc: 'Runtime environment', default: 'development', example: 'production' },
|
||||
{ name: 'DATABASE_URL', desc: 'SQLite database URL', default: 'file:data/gitea-mirror.db', example: 'file:path/to/database.db' },
|
||||
{ name: 'JWT_SECRET', desc: 'Secret key for JWT auth', default: 'Auto-generated', example: 'your-secure-string' },
|
||||
{ name: 'HOST', desc: 'Server host', default: 'localhost', example: '0.0.0.0' },
|
||||
{ name: 'PORT', desc: 'Server port', default: '4321', example: '8080' }
|
||||
];
|
||||
|
||||
const githubOptions = [
|
||||
{ name: 'Username', desc: 'Your GitHub username', default: '-' },
|
||||
{ name: 'Token', desc: 'GitHub personal access token (Classic PAT)', default: '-' },
|
||||
{ name: 'Private Repositories', desc: 'Include private repositories', default: 'false' },
|
||||
{ name: 'Mirror Starred', desc: 'Mirror repositories you\'ve starred', default: 'false' },
|
||||
{ name: 'Mirror Issues', desc: 'Mirror issues from GitHub to Gitea', default: 'false' },
|
||||
{ name: 'Mirror Wiki', desc: 'Mirror wiki pages from GitHub to Gitea', default: 'false' },
|
||||
{ name: 'Mirror Organizations', desc: 'Mirror organization repositories', default: 'false' },
|
||||
{ name: 'Only Mirror Orgs', desc: 'Only mirror organization repositories', default: 'false' },
|
||||
{ name: 'Skip Forks', desc: 'Exclude repositories that are forks', default: 'false' },
|
||||
{ name: 'Skip Starred Issues', desc: 'Skip issues for starred repositories', default: 'false' }
|
||||
];
|
||||
|
||||
const giteaOptions = [
|
||||
{ name: 'URL', desc: 'Gitea server URL', default: '-' },
|
||||
{ name: 'Token', desc: 'Gitea access token', default: '-' },
|
||||
{ name: 'Organization', desc: 'Default organization for mirrored repositories', default: '-' },
|
||||
{ name: 'Visibility', desc: 'Default visibility for mirrored repositories', default: 'public' },
|
||||
{ name: 'Starred Repos Org', desc: 'Organization for starred repositories', default: 'github' }
|
||||
];
|
||||
---
|
||||
|
||||
<MainLayout title="Configuration - Gitea Mirror">
|
||||
<main class="max-w-5xl mx-auto px-4 py-12">
|
||||
<div class="sticky top-4 z-10 mb-6">
|
||||
<a
|
||||
href="/docs/"
|
||||
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-card text-foreground hover:bg-muted transition-colors border border-border focus:ring-2 focus:ring-ring outline-none"
|
||||
>
|
||||
<span aria-hidden="true">←</span> Back to Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<article class="bg-card rounded-2xl shadow-lg p-6 md:p-8 border border-border">
|
||||
<!-- Header -->
|
||||
<div class="mb-12 space-y-4">
|
||||
<div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
</svg>
|
||||
<span>Configuration Guide</span>
|
||||
</div>
|
||||
<h1 class="text-4xl font-bold tracking-tight">Gitea Mirror Configuration</h1>
|
||||
<p class="text-lg text-muted-foreground leading-relaxed max-w-4xl">
|
||||
This guide provides detailed information on how to configure Gitea Mirror for your environment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Configuration Methods -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Configuration Methods</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
|
||||
<div class="bg-card rounded-lg border border-border p-6 hover:border-primary/50 transition-colors">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="text-2xl">🔧</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg mb-2">Environment Variables</h3>
|
||||
<p class="text-sm text-muted-foreground">Set configuration options through environment variables for automated deployments</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-6 hover:border-primary/50 transition-colors">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="text-2xl">🖥️</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg mb-2">Web UI</h3>
|
||||
<p class="text-sm text-muted-foreground">Configure the application through the web interface after installation</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Environment Variables -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Environment Variables</h2>
|
||||
|
||||
<p class="text-muted-foreground mb-6">The following environment variables can be used to configure Gitea Mirror:</p>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-border">
|
||||
<th class="text-left py-3 px-4 font-semibold">Variable</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Description</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Default</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Example</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{envVars.map((v, i) => (
|
||||
<tr class={`border-b border-border/50 hover:bg-muted/30 ${i === envVars.length - 1 ? 'border-b-0' : ''}`}>
|
||||
<td class="py-3 px-4">
|
||||
<code class="text-sm bg-muted px-1.5 py-0.5 rounded">{v.name}</code>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm text-muted-foreground">{v.desc}</td>
|
||||
<td class="py-3 px-4 text-sm"><code>{v.default}</code></td>
|
||||
<td class="py-3 px-4 text-sm"><code>{v.example}</code></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Security Note -->
|
||||
<div class="bg-amber-500/10 border border-amber-500/20 rounded-lg p-4 mt-6">
|
||||
<div class="flex gap-3">
|
||||
<div class="text-amber-600 dark:text-amber-500">
|
||||
<svg class="w-5 h-5 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold text-amber-600 dark:text-amber-500 mb-1">Security Note</h4>
|
||||
<p class="text-sm">The application will automatically generate a secure random <code class="bg-amber-500/10 px-1 py-0.5 rounded">JWT_SECRET</code> on first run if one isn't provided. This generated secret is stored in the data directory for persistence across container restarts.</p>
|
||||
<p class="text-sm mt-2">While this auto-generation feature provides good security by default, you can still explicitly set your own <code class="bg-amber-500/10 px-1 py-0.5 rounded">JWT_SECRET</code> for complete control over your deployment.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Web UI Configuration -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Web UI Configuration</h2>
|
||||
|
||||
<p class="text-muted-foreground mb-6">After installing and starting Gitea Mirror, you can configure it through the web interface:</p>
|
||||
|
||||
<div class="bg-gradient-to-r from-primary/5 to-transparent rounded-lg p-6 border-l-4 border-primary mb-8">
|
||||
<ol class="space-y-3">
|
||||
{[
|
||||
'Navigate to <code class="bg-muted px-1.5 py-0.5 rounded text-sm">http://your-server:port/</code>',
|
||||
'If this is your first time, you\'ll be guided through creating an admin account',
|
||||
'Log in with your credentials',
|
||||
'Go to the Configuration page'
|
||||
].map((step, i) => (
|
||||
<li class="flex gap-3">
|
||||
<span class="flex-shrink-0 w-6 h-6 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">{i + 1}</span>
|
||||
<span set:html={step}></span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- GitHub Configuration -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">GitHub Configuration</h3>
|
||||
<p class="text-muted-foreground mb-4">The GitHub configuration section allows you to connect to GitHub and specify which repositories to mirror.</p>
|
||||
|
||||
<div class="overflow-x-auto mb-6">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-border">
|
||||
<th class="text-left py-3 px-4 font-semibold">Option</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Description</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{githubOptions.map((opt, i) => (
|
||||
<tr class={`border-b border-border/50 hover:bg-muted/30 ${i === githubOptions.length - 1 ? 'border-b-0' : ''}`}>
|
||||
<td class="py-3 px-4 font-medium">{opt.name}</td>
|
||||
<td class="py-3 px-4 text-sm text-muted-foreground">{opt.desc}</td>
|
||||
<td class="py-3 px-4 text-sm"><code>{opt.default}</code></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- GitHub Token Permissions -->
|
||||
<div class="bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 mb-6">
|
||||
<div class="flex gap-3">
|
||||
<div class="text-blue-600 dark:text-blue-500">
|
||||
<svg class="w-5 h-5 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold text-blue-600 dark:text-blue-500 mb-2">Required Permissions</h4>
|
||||
<p class="text-sm mb-3">You need to create a <span class="font-semibold">Classic GitHub PAT Token</span> with the following scopes:</p>
|
||||
<ul class="space-y-1 text-sm">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-blue-600 dark:text-blue-500">•</span>
|
||||
<span><code class="bg-blue-500/10 px-1 py-0.5 rounded">repo</code> - Full control of private repositories</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-blue-600 dark:text-blue-500">•</span>
|
||||
<span><code class="bg-blue-500/10 px-1 py-0.5 rounded">admin:org</code> - Full control of orgs and teams, read and write org projects</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="text-sm mt-2">The organization access is required for mirroring organization repositories.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pl-4 border-l-2 border-primary/20">
|
||||
<h5 class="font-semibold mb-3">To create a GitHub token:</h5>
|
||||
<ol class="space-y-2 text-sm">
|
||||
<li>Go to <a href="https://github.com/settings/tokens" class="text-primary hover:underline">GitHub Settings > Developer settings > Personal access tokens</a></li>
|
||||
<li>Click "Generate new token"</li>
|
||||
<li>Select the required permissions</li>
|
||||
<li>Copy the generated token and paste it into Gitea Mirror</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gitea Configuration -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">Gitea Configuration</h3>
|
||||
<p class="text-muted-foreground mb-4">The Gitea configuration section allows you to connect to your Gitea instance and specify how repositories should be mirrored.</p>
|
||||
|
||||
<div class="overflow-x-auto mb-6">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-border">
|
||||
<th class="text-left py-3 px-4 font-semibold">Option</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Description</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{giteaOptions.map((opt, i) => (
|
||||
<tr class={`border-b border-border/50 hover:bg-muted/30 ${i === giteaOptions.length - 1 ? 'border-b-0' : ''}`}>
|
||||
<td class="py-3 px-4 font-medium">{opt.name}</td>
|
||||
<td class="py-3 px-4 text-sm text-muted-foreground">{opt.desc}</td>
|
||||
<td class="py-3 px-4 text-sm"><code>{opt.default}</code></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Mirror Strategies -->
|
||||
<div class="bg-gradient-to-r from-primary/5 to-transparent rounded-lg p-6 border-l-4 border-primary mb-6">
|
||||
<h4 class="font-semibold text-lg mb-4">Mirror Strategies</h4>
|
||||
<p class="text-sm text-muted-foreground mb-4">Choose how your repositories will be organized in Gitea:</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="bg-card rounded-lg border border-border p-4">
|
||||
<h5 class="font-semibold text-base mb-2 flex items-center gap-2">
|
||||
<span class="text-blue-600 dark:text-blue-500">📁</span>
|
||||
Preserve GitHub Structure
|
||||
</h5>
|
||||
<p class="text-sm text-muted-foreground mb-2">Maintains the exact structure from GitHub:</p>
|
||||
<ul class="space-y-1 text-sm ml-4">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<span>Personal repos → Your Gitea username</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<span>Organization repos → Same organization name in Gitea</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-4">
|
||||
<h5 class="font-semibold text-base mb-2 flex items-center gap-2">
|
||||
<span class="text-purple-600 dark:text-purple-500">🏢</span>
|
||||
Single Organization
|
||||
</h5>
|
||||
<p class="text-sm text-muted-foreground mb-2">Consolidates all repositories into one organization:</p>
|
||||
<ul class="space-y-1 text-sm ml-4">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<span>All repos → One designated organization</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<span>Requires setting "Organization" field</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-4">
|
||||
<h5 class="font-semibold text-base mb-2 flex items-center gap-2">
|
||||
<span class="text-green-600 dark:text-green-500">👤</span>
|
||||
Flat User Structure
|
||||
</h5>
|
||||
<p class="text-sm text-muted-foreground mb-2">Mirrors all repositories under your user account:</p>
|
||||
<ul class="space-y-1 text-sm ml-4">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<span>All repos → Your Gitea username</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-muted-foreground">•</span>
|
||||
<span>No organizations needed</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-amber-500/10 border border-amber-500/20 rounded-lg p-3 mt-4">
|
||||
<p class="text-sm">
|
||||
<span class="font-semibold">Note:</span> Starred repositories are always mirrored to the "Starred Repos Org" (default: "starred") regardless of the chosen strategy.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pl-4 border-l-2 border-primary/20">
|
||||
<h5 class="font-semibold mb-3">To create a Gitea access token:</h5>
|
||||
<ol class="space-y-2 text-sm">
|
||||
<li>Log in to your Gitea instance</li>
|
||||
<li>Go to Settings > Applications</li>
|
||||
<li>Under "Generate New Token", enter a name for your token</li>
|
||||
<li>Click "Generate Token"</li>
|
||||
<li>Copy the generated token and paste it into Gitea Mirror</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Schedule Configuration -->
|
||||
<div>
|
||||
<h3 class="text-xl font-semibold mb-4">Schedule Configuration</h3>
|
||||
<p class="text-muted-foreground mb-4">You can configure automatic mirroring on a schedule:</p>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-border">
|
||||
<th class="text-left py-3 px-4 font-semibold">Option</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Description</th>
|
||||
<th class="text-left py-3 px-4 font-semibold">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-border/50 hover:bg-muted/30">
|
||||
<td class="py-3 px-4 font-medium">Enable Scheduling</td>
|
||||
<td class="py-3 px-4 text-sm text-muted-foreground">Enable automatic mirroring</td>
|
||||
<td class="py-3 px-4 text-sm"><code>false</code></td>
|
||||
</tr>
|
||||
<tr class="hover:bg-muted/30">
|
||||
<td class="py-3 px-4 font-medium">Interval (seconds)</td>
|
||||
<td class="py-3 px-4 text-sm text-muted-foreground">Time between mirroring operations</td>
|
||||
<td class="py-3 px-4 text-sm"><code>3600</code> (1 hour)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Advanced Configuration -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Advanced Configuration</h2>
|
||||
|
||||
|
||||
<!-- Database Management -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">Database Management</h3>
|
||||
<p class="text-muted-foreground mb-4">Gitea Mirror includes several database management tools that can be run from the command line:</p>
|
||||
|
||||
<div class="bg-muted/30 rounded-lg p-4 overflow-x-auto">
|
||||
<pre class="text-sm whitespace-pre-wrap break-all"><code>{`# Initialize the database (only if it doesn't exist)
|
||||
bun run init-db
|
||||
|
||||
# Check database status
|
||||
bun run check-db
|
||||
|
||||
# Fix database location issues
|
||||
bun run fix-db
|
||||
|
||||
# Reset all users (for testing signup flow)
|
||||
bun run reset-users
|
||||
|
||||
# Remove database files completely
|
||||
bun run cleanup-db`}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Event Management -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">Event Management</h3>
|
||||
<p class="text-muted-foreground mb-4">Events in Gitea Mirror (such as repository mirroring operations) are stored in the SQLite database and can be viewed in the Activity Log page.</p>
|
||||
|
||||
<div class="bg-green-500/10 border border-green-500/20 rounded-lg p-4">
|
||||
<div class="flex gap-3">
|
||||
<div class="text-green-600 dark:text-green-500">
|
||||
<svg class="w-5 h-5 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm mb-2">Event Management Features:</p>
|
||||
<ul class="space-y-1 text-sm">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-green-600 dark:text-green-500">•</span>
|
||||
<span>View all events with filtering by type, status, and search</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-green-600 dark:text-green-500">•</span>
|
||||
<span>Real-time updates via Server-Sent Events (SSE)</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-green-600 dark:text-green-500">•</span>
|
||||
<span>Clean up old events using the cleanup button in the Activity Log</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-green-600 dark:text-green-500">•</span>
|
||||
<span>Automatic cleanup with configurable retention period</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Automatic Recovery System -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4">Automatic Recovery System</h3>
|
||||
<p class="text-muted-foreground mb-4">Gitea Mirror includes a robust recovery system that automatically handles interrupted operations:</p>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-6">
|
||||
<ul class="space-y-3">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<div>
|
||||
<span class="font-semibold">Startup Recovery:</span>
|
||||
<p class="text-sm text-muted-foreground mt-1">Automatically recovers interrupted jobs when the application starts</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<div>
|
||||
<span class="font-semibold">Graceful Shutdown:</span>
|
||||
<p class="text-sm text-muted-foreground mt-1">Saves job state before shutting down to enable recovery on restart</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<div>
|
||||
<span class="font-semibold">Job State Persistence:</span>
|
||||
<p class="text-sm text-muted-foreground mt-1">Stores mirror job progress in the database for resilience</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="mt-4 bg-muted/30 rounded-lg p-4 overflow-x-auto">
|
||||
<p class="text-sm font-medium mb-2">Manual recovery tools:</p>
|
||||
<pre class="text-sm whitespace-pre-wrap break-all"><code>{`# Run startup recovery manually
|
||||
bun run startup-recovery
|
||||
|
||||
# Fix interrupted jobs
|
||||
bun scripts/fix-interrupted-jobs.ts
|
||||
|
||||
# Test recovery system
|
||||
bun run test-recovery`}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Health Check Endpoint -->
|
||||
<div>
|
||||
<h3 class="text-xl font-semibold mb-4">Health Check Endpoint</h3>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-6">
|
||||
<h4 class="font-semibold mb-3">System Health Monitoring</h4>
|
||||
<p class="text-muted-foreground mb-4">Gitea Mirror includes a built-in health check endpoint at <code class="bg-muted px-1.5 py-0.5 rounded">/api/health</code> that provides:</p>
|
||||
|
||||
<ul class="space-y-2 mb-6">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<span>System status and uptime</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<span>Database connectivity check</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<span>Memory usage statistics</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-primary">✓</span>
|
||||
<span>Environment information</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="bg-muted/30 rounded-lg p-4 overflow-x-auto">
|
||||
<pre class="text-sm whitespace-pre-wrap break-all"><code>{`# Basic check (returns 200 OK if healthy)
|
||||
curl -I http://your-server:port/api/health
|
||||
|
||||
# Detailed health information (JSON)
|
||||
curl http://your-server:port/api/health`}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
</MainLayout>
|
||||
@@ -1,18 +1,37 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import MainLayout from '../../layouts/main.astro';
|
||||
import { LuSettings, LuRocket, LuBookOpen } from 'react-icons/lu';
|
||||
|
||||
// Helper to pick an icon based on doc.slug
|
||||
// We'll use inline conditional rendering instead of this function
|
||||
// Define our documentation pages directly
|
||||
const docs = [
|
||||
{
|
||||
slug: 'architecture',
|
||||
title: 'Architecture',
|
||||
description: 'Comprehensive overview of the Gitea Mirror application architecture.',
|
||||
order: 1,
|
||||
icon: LuBookOpen,
|
||||
href: '/docs/architecture'
|
||||
},
|
||||
{
|
||||
slug: 'configuration',
|
||||
title: 'Configuration',
|
||||
description: 'Guide to configuring Gitea Mirror for your environment.',
|
||||
order: 2,
|
||||
icon: LuSettings,
|
||||
href: '/docs/configuration'
|
||||
},
|
||||
{
|
||||
slug: 'quickstart',
|
||||
title: 'Quick Start Guide',
|
||||
description: 'Get started with Gitea Mirror quickly.',
|
||||
order: 3,
|
||||
icon: LuRocket,
|
||||
href: '/docs/quickstart'
|
||||
}
|
||||
];
|
||||
|
||||
// Get all documentation entries, sorted by order
|
||||
const docs = await getCollection('docs');
|
||||
const sortedDocs = docs.sort((a, b) => {
|
||||
const orderA = a.data.order || 999;
|
||||
const orderB = b.data.order || 999;
|
||||
return orderA - orderB;
|
||||
});
|
||||
// Sort by order
|
||||
const sortedDocs = docs.sort((a, b) => a.order - b.order);
|
||||
---
|
||||
|
||||
<MainLayout title="Documentation">
|
||||
@@ -21,24 +40,25 @@ const sortedDocs = docs.sort((a, b) => {
|
||||
<p class="mb-10 text-lg text-muted-foreground text-center">Browse guides and technical docs for Gitea Mirror.</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
{sortedDocs.map(doc => (
|
||||
<a
|
||||
href={`/docs/${doc.slug}`}
|
||||
class="group block p-7 border border-border rounded-2xl bg-card hover:bg-muted transition-colors shadow-lg focus:ring-2 focus:ring-ring outline-none"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<div class="w-10 h-10 bg-muted rounded-full flex items-center justify-center text-muted-foreground">
|
||||
{doc.slug === 'architecture' && <LuBookOpen className="w-5 h-5" />}
|
||||
{doc.slug === 'configuration' && <LuSettings className="w-5 h-5" />}
|
||||
{doc.slug === 'quickstart' && <LuRocket className="w-5 h-5" />}
|
||||
{!['architecture', 'configuration', 'quickstart'].includes(doc.slug) && <LuBookOpen className="w-5 h-5" />}
|
||||
{sortedDocs.map(doc => {
|
||||
const Icon = doc.icon;
|
||||
|
||||
return (
|
||||
<a
|
||||
href={doc.href}
|
||||
class="group block p-7 border border-border rounded-2xl bg-card hover:bg-muted transition-colors shadow-lg focus:ring-2 focus:ring-ring outline-none"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<div class="w-10 h-10 bg-muted rounded-full flex items-center justify-center text-muted-foreground">
|
||||
<Icon className="w-5 h-5" />
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold group-hover:text-foreground transition">{doc.title}</h2>
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold group-hover:text-foreground transition">{doc.data.title}</h2>
|
||||
</div>
|
||||
<p class="text-muted-foreground">{doc.data.description}</p>
|
||||
</a>
|
||||
))}
|
||||
<p class="text-muted-foreground">{doc.description}</p>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</main>
|
||||
</MainLayout>
|
||||
</MainLayout>
|
||||
437
src/pages/docs/quickstart.astro
Normal file
437
src/pages/docs/quickstart.astro
Normal file
@@ -0,0 +1,437 @@
|
||||
---
|
||||
import MainLayout from '../../layouts/main.astro';
|
||||
---
|
||||
|
||||
<MainLayout title="Quick Start Guide - Gitea Mirror">
|
||||
<main class="max-w-5xl mx-auto px-4 py-12">
|
||||
<div class="sticky top-4 z-10 mb-6">
|
||||
<a
|
||||
href="/docs/"
|
||||
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-card text-foreground hover:bg-muted transition-colors border border-border focus:ring-2 focus:ring-ring outline-none"
|
||||
>
|
||||
<span aria-hidden="true">←</span> Back to Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<article class="bg-card rounded-2xl shadow-lg p-6 md:p-8 border border-border">
|
||||
<!-- Header -->
|
||||
<div class="mb-12 space-y-4">
|
||||
<div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
|
||||
</svg>
|
||||
<span>Quick Start</span>
|
||||
</div>
|
||||
<h1 class="text-4xl font-bold tracking-tight">Gitea Mirror Quick Start Guide</h1>
|
||||
<p class="text-lg text-muted-foreground leading-relaxed max-w-4xl">
|
||||
This guide will help you get Gitea Mirror up and running quickly.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Prerequisites -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Prerequisites</h2>
|
||||
|
||||
<div class="bg-gradient-to-r from-primary/5 to-transparent rounded-lg p-6 border-l-4 border-primary mb-8">
|
||||
<h3 class="font-semibold mb-4">Before you begin, make sure you have:</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex-shrink-0 w-6 h-6 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">1</div>
|
||||
<div>
|
||||
<span class="font-semibold text-foreground">A GitHub account with a personal access token</span>
|
||||
<p class="text-sm text-muted-foreground mt-1">Create one at <a href="https://github.com/settings/tokens" class="text-primary hover:underline">GitHub Settings</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex-shrink-0 w-6 h-6 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">2</div>
|
||||
<div>
|
||||
<span class="font-semibold text-foreground">A Gitea instance with an access token</span>
|
||||
<p class="text-sm text-muted-foreground mt-1">Available in your Gitea Settings > Applications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex-shrink-0 w-6 h-6 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">3</div>
|
||||
<div>
|
||||
<span class="font-semibold text-foreground">One of the following:</span>
|
||||
<ul class="mt-2 space-y-1 text-sm text-muted-foreground pl-4">
|
||||
<li class="flex gap-2"><span>•</span> Docker and docker-compose (for Docker deployment)</li>
|
||||
<li class="flex gap-2"><span>•</span> Bun 1.2.9+ (for native deployment)</li>
|
||||
<li class="flex gap-2"><span>•</span> Proxmox VE or LXD (for LXC container deployment)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Installation Options -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Installation Options</h2>
|
||||
<p class="text-muted-foreground mb-8">Choose the installation method that works best for your environment.</p>
|
||||
|
||||
<!-- Docker Installation -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4 flex items-center gap-2">
|
||||
🐳 Using Docker <span class="text-sm text-muted-foreground font-normal">(Recommended for most users)</span>
|
||||
</h3>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-6">
|
||||
<p class="text-muted-foreground mb-4">Docker provides the easiest way to get started with minimal configuration.</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
{[
|
||||
{ step: 'Clone the repository', cmd: 'git clone https://github.com/arunavo4/gitea-mirror.git\ncd gitea-mirror' },
|
||||
{ step: 'Start the application in production mode', cmd: 'docker compose up -d' },
|
||||
{ step: 'Access the application', cmd: null, text: 'Open your browser and navigate to <a href="http://localhost:4321" class="text-primary hover:underline font-medium">http://localhost:4321</a>' }
|
||||
].map((item, i) => (
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-sm font-semibold text-muted-foreground">STEP {i + 1}</span>
|
||||
<span class="text-sm text-muted-foreground">{item.step}</span>
|
||||
</div>
|
||||
{item.cmd ? (
|
||||
<div class="bg-muted/30 rounded-lg p-4">
|
||||
<pre class="text-sm"><code>{item.cmd}</code></pre>
|
||||
</div>
|
||||
) : (
|
||||
<p class="text-sm" set:html={item.text}></p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bun Installation -->
|
||||
<div class="mb-8">
|
||||
<h3 class="text-xl font-semibold mb-4 flex items-center gap-2">
|
||||
🏃 Using Bun <span class="text-sm text-muted-foreground font-normal">(Native Installation)</span>
|
||||
</h3>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-6">
|
||||
<p class="text-muted-foreground mb-4">If you prefer to run the application directly on your system:</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-sm font-semibold text-muted-foreground">STEP 1</span>
|
||||
<span class="text-sm text-muted-foreground">Clone the repository</span>
|
||||
</div>
|
||||
<div class="bg-muted/30 rounded-lg p-4">
|
||||
<pre class="text-sm"><code>git clone https://github.com/arunavo4/gitea-mirror.git
|
||||
cd gitea-mirror</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-sm font-semibold text-muted-foreground">STEP 2</span>
|
||||
<span class="text-sm text-muted-foreground">Run the quick setup script</span>
|
||||
</div>
|
||||
<div class="bg-muted/30 rounded-lg p-4">
|
||||
<pre class="text-sm"><code>bun run setup</code></pre>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground mt-2">This installs dependencies and initializes the database.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-sm font-semibold text-muted-foreground">STEP 3</span>
|
||||
<span class="text-sm text-muted-foreground">Choose how to run the application</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-3">
|
||||
<div class="border border-border rounded-lg p-4">
|
||||
<h5 class="font-semibold mb-2">Development Mode</h5>
|
||||
<div class="bg-muted/30 rounded-lg p-3 text-sm">
|
||||
<pre><code>bun run dev</code></pre>
|
||||
</div>
|
||||
<p class="text-xs text-muted-foreground mt-2">For Bun-specific features, use: <code class="bg-muted px-1 rounded">bunx --bun astro dev</code></p>
|
||||
</div>
|
||||
|
||||
<div class="border border-border rounded-lg p-4">
|
||||
<h5 class="font-semibold mb-2">Production Mode</h5>
|
||||
<div class="bg-muted/30 rounded-lg p-3 text-sm">
|
||||
<pre><code>bun run build
|
||||
bun run start</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-sm font-semibold text-muted-foreground">STEP 4</span>
|
||||
<span class="text-sm text-muted-foreground">Access the application</span>
|
||||
</div>
|
||||
<p class="text-sm">Open your browser and navigate to <a href="http://localhost:4321" class="text-primary hover:underline font-medium">http://localhost:4321</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LXC Installation -->
|
||||
<div>
|
||||
<h3 class="text-xl font-semibold mb-4 flex items-center gap-2">
|
||||
📦 Using LXC Containers <span class="text-sm text-muted-foreground font-normal">(Recommended for Proxmox VE)</span>
|
||||
</h3>
|
||||
|
||||
<div class="bg-card rounded-lg border border-border p-6">
|
||||
<div class="space-y-4">
|
||||
<h4 class="font-semibold flex items-center gap-2">
|
||||
<span>Proxmox VE Installation</span>
|
||||
<span class="text-xs text-muted-foreground font-normal">(Community Script)</span>
|
||||
</h4>
|
||||
|
||||
<p class="text-sm text-muted-foreground mb-4">Deploy Gitea Mirror on Proxmox VE using the community-maintained script:</p>
|
||||
|
||||
<div class="bg-muted/30 rounded-lg p-4 overflow-x-auto">
|
||||
<pre class="text-sm whitespace-pre-wrap break-all"><code>bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/gitea-mirror.sh)"</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-sm text-muted-foreground">
|
||||
<p class="font-medium mb-2">This script will:</p>
|
||||
<ul class="space-y-1 pl-4">
|
||||
<li class="flex gap-2"><span>•</span> Create a privileged Alpine Linux LXC container</li>
|
||||
<li class="flex gap-2"><span>•</span> Install Bun runtime and dependencies</li>
|
||||
<li class="flex gap-2"><span>•</span> Clone and build Gitea Mirror</li>
|
||||
<li class="flex gap-2"><span>•</span> Configure systemd service for automatic startup</li>
|
||||
<li class="flex gap-2"><span>•</span> Set up the application to run on port 4321</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg">
|
||||
<div class="flex gap-3">
|
||||
<div class="text-blue-600 dark:text-blue-500">
|
||||
<svg class="w-5 h-5 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<p class="font-semibold text-blue-600 dark:text-blue-500 mb-1">Note</p>
|
||||
<p>After installation, access Gitea Mirror at <code class="bg-blue-500/10 px-1 py-0.5 rounded">http://<container-ip>:4321</code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 pt-4 border-t border-border">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
For more information about the community script, visit the
|
||||
<a href="https://community-scripts.github.io/ProxmoxVE/scripts?id=gitea-mirror" class="text-primary hover:underline">Community Scripts documentation</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Initial Configuration -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Initial Configuration</h2>
|
||||
<p class="text-muted-foreground mb-6">Follow these steps to configure Gitea Mirror for first use:</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{[
|
||||
{
|
||||
num: '1',
|
||||
title: 'Create Admin Account',
|
||||
items: [
|
||||
"You'll be prompted on first access",
|
||||
'Choose a secure username and password',
|
||||
'This will be your administrator account'
|
||||
]
|
||||
},
|
||||
{
|
||||
num: '2',
|
||||
title: 'Configure GitHub Connection',
|
||||
items: [
|
||||
'Navigate to the Configuration page',
|
||||
'Enter your GitHub credentials',
|
||||
'Select repositories to mirror',
|
||||
'Configure filtering options'
|
||||
]
|
||||
},
|
||||
{
|
||||
num: '3',
|
||||
title: 'Configure Gitea Connection',
|
||||
items: [
|
||||
'Enter your Gitea server URL',
|
||||
'Enter your Gitea access token',
|
||||
'Configure organization settings',
|
||||
'Set default visibility'
|
||||
]
|
||||
},
|
||||
{
|
||||
num: '4',
|
||||
title: 'Set Up Scheduling',
|
||||
items: [
|
||||
'Enable automatic mirroring',
|
||||
'Set the mirroring interval',
|
||||
'Save your configuration'
|
||||
]
|
||||
}
|
||||
].map(step => (
|
||||
<div class="bg-card rounded-lg border border-border p-4 hover:border-primary/50 transition-colors">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="flex-shrink-0 w-8 h-8 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">{step.num}</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-1">{step.title}</h4>
|
||||
<ul class="text-sm text-muted-foreground space-y-1">
|
||||
{step.items.map(item => (
|
||||
<li>• {item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Performing Your First Mirror -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Performing Your First Mirror</h2>
|
||||
|
||||
<div class="bg-gradient-to-r from-primary/5 to-transparent rounded-lg p-6 border-l-4 border-primary">
|
||||
<h3 class="font-semibold mb-4">After completing the configuration, you can start mirroring repositories:</h3>
|
||||
|
||||
<ol class="space-y-3">
|
||||
{[
|
||||
'Click <strong>"Import GitHub Data"</strong> to fetch repositories from GitHub',
|
||||
'Go to the <strong>Repositories</strong> page to view your imported repositories',
|
||||
'Select the repositories you want to mirror',
|
||||
'Click <strong>"Mirror Selected"</strong> to start the mirroring process',
|
||||
'Monitor the progress on the <strong>Activity</strong> page',
|
||||
"You'll receive toast notifications about the success or failure of operations"
|
||||
].map((step, i) => (
|
||||
<li class="flex gap-3">
|
||||
<span class="flex-shrink-0 w-6 h-6 bg-primary/10 rounded-full flex items-center justify-center text-sm font-semibold">{i + 1}</span>
|
||||
<span set:html={step}></span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Troubleshooting -->
|
||||
<section class="mb-12">
|
||||
<h2 class="text-2xl font-bold mb-6">Troubleshooting</h2>
|
||||
|
||||
<div class="bg-amber-500/10 border border-amber-500/20 rounded-lg p-4">
|
||||
<div class="flex gap-3">
|
||||
<div class="text-amber-600 dark:text-amber-500">
|
||||
<svg class="w-5 h-5 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<h4 class="font-semibold text-amber-600 dark:text-amber-500">If you encounter any issues:</h4>
|
||||
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex gap-2">
|
||||
<span class="text-amber-600 dark:text-amber-500">•</span>
|
||||
<span>Check the <strong>Activity Log</strong> for detailed error messages</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<span class="text-amber-600 dark:text-amber-500">•</span>
|
||||
<span>Verify your GitHub and Gitea tokens have the correct permissions</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<span class="text-amber-600 dark:text-amber-500">•</span>
|
||||
<span>Ensure your Gitea instance is accessible from the machine running Gitea Mirror</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 space-y-3">
|
||||
<h5 class="font-semibold">Check logs based on your deployment method:</h5>
|
||||
|
||||
<div class="bg-amber-500/5 rounded-lg p-3 space-y-2">
|
||||
<div class="grid grid-cols-1 gap-2 text-sm">
|
||||
<div>
|
||||
<span class="font-medium">Docker:</span>
|
||||
<code class="bg-amber-500/10 px-1.5 py-0.5 rounded ml-2">docker logs gitea-mirror</code>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">Native:</span>
|
||||
<span class="text-muted-foreground ml-2">Check terminal output or system logs</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium">LXC:</span>
|
||||
<code class="bg-amber-500/10 px-1.5 py-0.5 rounded ml-2">systemctl status gitea-mirror</code>
|
||||
<span class="text-muted-foreground ml-1">or</span>
|
||||
<code class="bg-amber-500/10 px-1.5 py-0.5 rounded ml-1">journalctl -u gitea-mirror -f</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex gap-2">
|
||||
<span class="text-amber-600 dark:text-amber-500">•</span>
|
||||
<span>Use the health check endpoint: <code class="bg-amber-500/10 px-1.5 py-0.5 rounded">curl http://your-server:4321/api/health</code></span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<span class="text-amber-600 dark:text-amber-500">•</span>
|
||||
<span>For database issues: <code class="bg-amber-500/10 px-1.5 py-0.5 rounded">bun run check-db</code> or <code class="bg-amber-500/10 px-1.5 py-0.5 rounded">bun run fix-db</code></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="my-12 h-px bg-border/50"></div>
|
||||
|
||||
<!-- Next Steps -->
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold mb-6">Next Steps</h2>
|
||||
|
||||
<div class="bg-gradient-to-br from-primary/5 via-transparent to-primary/5 rounded-lg p-6 border border-border">
|
||||
<h3 class="font-semibold mb-4">After your initial setup:</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="space-y-3">
|
||||
{[
|
||||
'Explore the dashboard for an overview of your mirroring status',
|
||||
'Set up automatic mirroring schedules for hands-off operation',
|
||||
'Configure organization mirroring for team repositories',
|
||||
'Use the cleanup button in Activity Log to manage old events'
|
||||
].map(item => (
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary">✓</span>
|
||||
<span>{item}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary">📖</span>
|
||||
<span>Check out the <a href="/docs/configuration" class="text-primary hover:underline font-medium">Configuration Guide</a> for advanced settings</span>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary">🏗️</span>
|
||||
<span>Review the <a href="/docs/architecture" class="text-primary hover:underline font-medium">Architecture Documentation</a> to understand the system</span>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<span class="text-primary">📊</span>
|
||||
<span>For server deployments, set up monitoring using the health check endpoint</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
</MainLayout>
|
||||
Reference in New Issue
Block a user