A high-performance, secure Git API gateway and multi-framework auto-updater proxy for client applications (Tauri, Wails, Electron, and more). It enables desktop and client apps to seamlessly interact with private and public Git repositories (fetching raw files, batch assets, localized release notes, and updates) without exposing secret API tokens or communicating directly with Git provider APIs.
Supported platforms include GitHub (Cloud & Enterprise Server), GitLab (Cloud & Self-Managed), Gitea / Forgejo / Codeberg, GitVerse, GitFlic, Bitbucket Cloud, Azure DevOps, and OneDev.
It shields your access tokens from end-users, streams installer downloads, handles multi-channel releases (stable and prerelease), and serves markdown/MDX release notes with full BCP 47 i18n support.
- Multi-Provider Support: First-class support for GitHub, GitLab, Gitea, Forgejo, Codeberg, GitVerse, GitFlic, Bitbucket, Azure DevOps, and OneDev (including self-hosted/enterprise instances).
- Token Security: Hides credentials from client apps; end-users never see or need API tokens.
- Multi-Framework Auto-Updates (
/api/v1/update/{framework}/...):- Tauri: Natively compatible with Tauri v1 and Tauri v2 (
/api/v1/update/tauri/:target/:versionandlatest.json) with automatic protocol version negotiation. - Wails v3: Fully compatible with official Wails v3 Update Manifest Protocol and in-place binary swapping.
- Electron, Sparkle & Generic: Designed for extensible multi-platform update distribution.
- Tauri: Natively compatible with Tauri v1 and Tauri v2 (
- Multi-Channel Releases: Segregates
stableandprerelease(beta/alpha) channels. - Flexible Channel Selection: Supports channel selection via HTTP header (
X-Update-Channel) or query parameter, with well-defined priority. - Binary Streaming: Efficiently proxies binary downloads (
.exe,.zip,.sig,.dmg, etc.) directly from release assets without memory bloat (/api/v1/download). - Raw & Batch Files (
/api/v1/file,/api/v1/files): Fetch single raw files or batch requests with automatic text/binary encoding from repository branches/tags. - Rich Release Notes System (
/api/v1/release-notes): Serves dedicated version release notes written in Markdown or MDX (release-notes/<version>.mdx), with full YAML frontmatter parsing (title,date,tags), multi-language BCP 47 localization support, and automatic fallbacks to provider release notes when needed. - Pure & Clean REST Architecture: Structured around canonical
/api/v1/*endpoints without URL legacy pollution.
All endpoints use the canonical /api/v1 prefix.
GET /api/v1/update/tauri/:target/:versionPrimary update endpoint for Tauri applications (supporting both Tauri v1 and Tauri v2).
- Route Parameters:
:target— Target platform identifier (e.g.windows-x86_64,windows-aarch64,darwin-aarch64,linux-x86_64).:version— Currently installed client version (e.g.1.3.1,1.4.0-beta.1).
- Framework Protocol Negotiation:
Automatically determines whether to return Tauri v1 format (flat JSON) or Tauri v2 format (nested
platforms[target]) via Content Negotiation (X-Framework-Version>Accept>User-Agent> default: v2). - Channel Selection: via
?channel=query parameter orX-Update-Channelheader. - Responses:
204 No Content: The client is already running the latest version.200 OK: A new version is available. Returns update metadata with secure download links pointing to/api/v1/download?asset_id=....
GET /api/v1/update/tauri/latest.json
GET /api/v1/update/tauri/latest.:channel.jsonServes release manifests (latest.json, latest.stable.json, latest.prerelease.json) according to the MANIFEST_SOURCE strategy (auto, releases, or repo).
GET /api/v1/update/wails/check?platform=:goos&arch=:goarch&version=:version
GET /api/v1/update/wails/manifest.json
GET /api/v1/update/wails/manifest.:channel.jsonEndpoint for official Wails v3 Update Manifest Protocol and in-place binary swapping.
- Query Parameters (for
/check):platform— Target OS (windows,darwin,linux).arch— Architecture (amd64,arm64,386,arm).version— Installed version (e.g.1.0.0).
- Responses:
204 No Content: The client is already running the latest version.200 OK: JSON manifest with target platforms, SHA-256 checksums, signatures, and secured binary download URLs.
GET /api/v1/update/electron/:fileServes YAML manifests for electron-updater (e.g. latest.yml, latest-mac.yml, latest-linux.yml, beta.yml).
- Automatically rewrites release URLs to the secure
/api/v1/downloadproxy. - Dynamically generates the manifest with SHA-512 hashes if
.ymlwas not pre-generated.
GET /api/v1/update/sparkle/appcast.xmlServes an RSS 2.0 XML appcast feed with xmlns:sparkle schema, EdDSA signatures (sparkle:edSignature), enclosure binary downloads, and links to release notes.
GET /api/v1/update/generic/check?version=:version&target=:target&arch=:archUniversal update check endpoint for custom client apps, mobile clients, and CLI tools.
- Returns a standardized JSON object with
has_update,current_version,latest_version, andassetmetadata (download URL, SHA checksum, size).
GET /api/v1/download?asset_id=:idSecurely proxies the release binary asset download from the Git provider.
- Query Parameters:
asset_id— Provider release asset identifier.
- Response:
- Streams or redirects to the file with
Content-Type: application/octet-streamand properContent-Disposition.
- Streams or redirects to the file with
GET /api/v1/release-notes/:versionFetches the release notes for a specific version, with full multi-language (i18n) localization support.
- Route Parameters:
:version— Version string (e.g.1.3.1,v1.3.1,1.4.0-beta.1).
- Language / Locale Selection:
?lang=query parameter (highest priority, e.g.?lang=pt-BR,?lang=ru,?lang=en).X-App-LanguageHTTP header (e.g.X-App-Language: pt-BR).- Falls back to
FALLBACK_LANGUAGE(oren).
GET /api/v1/release-notesReturns an array of all available versions that have release notes files in <RELEASE_NOTES_DIR> (sorted descending by SemVer 2.0).
GET /api/v1/file/:path*
GET /api/v1/file?path=:path&ref=:refFetches the raw contents of any file from the repository, securely streaming or sending it with the appropriate Content-Type header without exposing access tokens.
POST /api/v1/files?ref=:ref
GET /api/v1/files?paths=:path1,:path2&ref=:refRetrieves multiple files in a single network request as a JSON object (text files encoded in utf-8, binary in base64).
- Parameters:
ref(optional) — Git branch, tag, or commit hash (defaults toREPO_BRANCH).paths— Array of file paths (via JSON body{"paths": [...]}inPOST) or comma-separated string inGET. Maximum 50 files per request.
- Response Example:
{ "ref": "main", "files": { "package.json": { "content": "{\n \"name\": \"my-app\" ... }", "contentType": "application/json; charset=utf-8", "encoding": "utf-8", "size": 1240 }, "assets/icon.png": { "content": "iVBORw0KGgoAAAANSUhEUgAA...", "contentType": "image/png", "encoding": "base64", "size": 5432 } }, "errors": { "missing-file.txt": "Not Found" } }
Channel names are fully arbitrary strings (e.g. stable, prerelease, alpha, beta, nightly, canary, preview, dev) and are not restricted to a fixed set:
stable(reserved keyword, default): Exclusively serves official, non-prerelease releases. Any release marked as draft or pre-release is filtered out.- Any other channel name (e.g.
prerelease,alpha,beta,nightly,canary, etc.):- In
/update/:target/:version: Activates pre-release eligibility, serving pre-release builds if newer than the client version. If a newer final stable release is published, pre-release clients also receive it. - In
/latest.json: Dynamically looks forlatest.<channel>.jsonin the repository (e.g.channel=nightlylooks forlatest.nightly.json,channel=alphalooks forlatest.alpha.json), automatically falling back tolatest.jsonif the channel file does not exist.
- In
When determining the release channel, the server applies the following priority order:
- Query Parameter (
?channel=...): Takes highest precedence. Useful for manual testing, browser links, and direct overrides. - HTTP Header (
X-Update-Channel: ...): Used by automated client libraries (like Tauri v2check({ headers })). - Default (
stable): Used when neither the query parameter nor the header is provided.
Pass the headers option to check() in @tauri-apps/plugin-updater:
import { check } from '@tauri-apps/plugin-updater';
// Check for stable updates (default)
const update = await check({
headers: {
'X-Update-Channel': 'stable',
},
});
// Check for pre-release / beta updates
const betaUpdate = await check({
headers: {
'X-Update-Channel': 'prerelease',
},
});Endpoints like /api/v1/update/tauri/:target/:version dynamically negotiate the protocol format to cleanly serve clients running different framework generations without polluting URL paths:
- Tauri v1 Protocol: Flat JSON with top-level
url,version,signature, andnotes. - Tauri v2 Protocol (default): Nested JSON containing
platforms[target]withurlandsignature.
When determining the client protocol version, the server applies the following order of precedence:
-
Query Parameter (
?framework_version=...): Explicit override, e.g.?framework_version=1. -
HTTP Header (
X-Framework-Version: ...): Explicit framework protocol version, e.g.X-Framework-Version: 1. -
Accept Header (
Accept: application/vnd.tauri.v1+json): Standard REST vendor MIME type. -
User-Agent Heuristic:
-
tauri-plugin-updater$\to$ Tauri v2 protocol. -
tauri-updater(or Tauri v1 client)$\to$ Tauri v1 protocol.
-
- Default: Latest stable protocol version (Tauri v2).
Configure these variables in your deployment environment (e.g. Vercel Project Settings):
| Variable | Required | Default | Description |
|---|---|---|---|
GIT_PROVIDER |
No | github |
Git provider: github, gitlab, gitea, gitverse, gitflic, bitbucket, azure_devops, or onedev. |
GIT_TOKEN |
Yes | — | Personal Access Token with repository read access. |
REPO_OWNER |
Yes | — | Repository owner / group / organization. For Azure DevOps: org or org/project. |
REPO_NAME |
Yes | — | Repository / project name. |
GIT_API_URL |
No | — | Custom API Base URL for self-hosted instances (e.g. https://gitlab.mycompany.com/api/v4, https://github.corp.com/api/v3, https://codeberg.org/api/v1). Auto-detected if empty. |
REPO_BRANCH |
No | main |
Target repository branch for fetching manifests (latest*.json) and release notes. |
MANIFEST_SOURCE |
No | auto |
Manifest resolution strategy: auto (release assets first, fallback to repo), releases (only release assets), or repo (only repository files). |
MANIFESTS_DIR |
No | "" (root) |
Target directory in repository where release manifests (latest*.json) are located (used when served from repository). |
RELEASE_NOTES_DIR |
No | release-notes |
Target directory in repository where release notes (.md / .mdx) are located. |
RELEASE_NOTES_DIR_STRUCTURE |
No | auto |
Directory layout for release notes: auto (nested first, fallback to flat), nested, or flat. |
FALLBACK_LANGUAGE |
No | en |
Fallback language / locale when requested translation is unavailable (e.g. en, en-US, ru). |
GIT_PROVIDER=github
GIT_TOKEN=ghp_yourPersonalAccessTokenHere
REPO_OWNER=my-org
REPO_NAME=my-appFor GitHub Enterprise Server: set GIT_API_URL=https://github.mycompany.com/api/v3.
GIT_PROVIDER=gitlab
GIT_TOKEN=glpat-yourPersonalAccessTokenHere
REPO_OWNER=my-group
REPO_NAME=my-appFor GitLab Self-Managed: set GIT_API_URL=https://gitlab.mycompany.com/api/v4.
GIT_PROVIDER=gitea
GIT_TOKEN=your_gitea_token
REPO_OWNER=my-org
REPO_NAME=my-app
GIT_API_URL=https://codeberg.org/api/v1 # or https://gitea.mycompany.com/api/v1GIT_PROVIDER=gitverse
GIT_TOKEN=your_gitverse_token
REPO_OWNER=my-org
REPO_NAME=my-appPre-configured with https://gitverse.ru/api/v1.
GIT_PROVIDER=gitflic
GIT_TOKEN=your_gitflic_token
REPO_OWNER=my-alias
REPO_NAME=my-projectPre-configured with https://api.gitflic.ru (set GIT_API_URL for self-hosted GitFlic Enterprise).
GIT_PROVIDER=bitbucket
GIT_TOKEN=your_app_password_or_token # For Basic auth: username:app_password
REPO_OWNER=my-workspace
REPO_NAME=my-repoGIT_PROVIDER=azure_devops
GIT_TOKEN=your_azure_personal_access_token
REPO_OWNER=my-organization/my-project
REPO_NAME=my-repoGIT_PROVIDER=onedev
GIT_TOKEN=your_onedev_access_token
REPO_OWNER=my-group
REPO_NAME=my-project
GIT_API_URL=https://code.onedev.io/~api # or https://onedev.mycompany.com/~api-
Create a Git repository (e.g.
git-gateway) and push this project. -
Log in to Vercel and click Add New -> Project.
-
Select your repository, leave Framework Preset as Other, and click Deploy.
-
In the Vercel Dashboard, go to Settings -> Environment Variables and add your provider configuration (e.g.
GIT_PROVIDER,GIT_TOKEN,REPO_OWNER,REPO_NAME). -
Deployment Protection / OPTIONS Allowlist (Required if Deployment Protection is enabled):
If Vercel Deployment Protection (or Vercel Authentication) is enabled on your project or preview deployments, allow CORS preflight (OPTIONS) requests so client applications (such as Tauri Webviews or web frontends) can reach the API without 401 Unauthorized or redirect errors.Because Vercel limits the OPTIONS Allowlist to a maximum of 4 paths, all endpoints use the common
/apiprefix (e.g./api/v1/update/tauri/v2/...,/api/v1/download,/api/v1/files):- Go to Project Settings -> Deployment Protection -> OPTIONS Allowlist (see Vercel Documentation).
- Add the following path to the allowlist:
/api
-
Redeploy the latest deployment to apply the environment variables and settings.
You can run the proxy completely self-hosted using Docker and Compose without any dependency on Vercel:
# 1. Copy and edit environment configuration
cp .env.example .env
# 2. Build and run via Compose (includes Nginx reverse proxy)
docker compose up -d --buildFor full setup, architecture details, and SSL configuration, see the Docker Deployment Guide.
In your Tauri project's tauri.conf.json, specify your proxy endpoint:
"plugins": {
"updater": {
"pubkey": "<your-tauri-pubkey>",
"endpoints": [
"https://your-proxy.vercel.app/api/v1/update/tauri/v2/{{target}}/{{current_version}}"
]
}
}