Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/CspmIT/mas-agua-front/llms.txt

Use this file to discover all available pages before exploring further.

The Mas Agua desktop application uses Tauri’s built-in updater plugin to deliver seamless automatic updates from GitHub Releases.

How It Works

  1. Application checks for updates on startup or manually
  2. Updater queries GitHub Releases for latest.json manifest
  3. If new version available, download update bundle
  4. Verify signature using public key
  5. Install update and relaunch application

Configuration

Tauri Configuration

From src-tauri/tauri.conf.json:38-45:
{
  "plugins": {
    "updater": {
      "active": true,
      "endpoints": [
        "https://github.com/CspmIT/mas-agua-front/releases/latest/download/latest.json"
      ],
      "dialog": true,
      "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IENFOUE0OEYyMDA5NDkyNEQKUldSTmtwUUE4a2lhenBraVNOd2cwOU1ZbkxWdVJTU0lEbUZiTkp0VTFRenhtdndVZ1VwUlQ4OG0K"
    }
  }
}
Configuration Options:
  • active: Enable/disable updater (true)
  • endpoints: Array of URLs to check for updates
  • dialog: Show built-in update dialog (true)
  • pubkey: Public key for signature verification (base64 encoded)

Rust Backend Setup

From src-tauri/src/main.rs:8:
.plugin(tauri_plugin_updater::Builder::new().build())
The updater plugin is initialized in the Tauri builder.

Security Capabilities

From src-tauri/tauri.conf.json:28-35:
{
  "security": {
    "capabilities": [
      {
        "identifier": "store-access",
        "windows": ["main"],
        "platforms": ["linux", "macOS", "windows"],
        "permissions": [
          "store:default",
          "process:default",
          "updater:default",
          "core:app:allow-version"
        ]
      }
    ]
  }
}
The updater:default permission grants access to the updater API.

Frontend Implementation

Update Hook

From src/hooks/useUpdater.js:
import { check } from '@tauri-apps/plugin-updater'
import { relaunch } from '@tauri-apps/plugin-process'
import Swal from 'sweetalert2'
import { 
  showInstallMessage, 
  showUpdateError, 
  showUpdateProgress, 
  updateProgress 
} from '../utils/js/updateSwal'

export const useUpdater = () => {
  const checkForUpdates = async () => {
    try {
      // Check for available updates
      const update = await check()
      
      if (!update) return
      
      // Show confirmation dialog
      const confirm = await Swal.fire({
        title: 'Nueva versión disponible',
        text: '¿Deseás actualizar ahora?',
        icon: 'info',
        showCancelButton: true,
        confirmButtonText: 'Actualizar',
        cancelButtonText: 'Más tarde',
      })
      
      if (!confirm.isConfirmed) return
      
      // Download and install
      let downloaded = 0
      let contentLength = 0
      let downloadStarted = false
      
      showUpdateProgress()
      
      const timeoutId = setTimeout(() => {
        if (!downloadStarted) {
          Swal.fire({
            icon: 'error',
            title: 'No se pudo descargar la actualización',
            text: 'Intenta nuevamente o descárgala manualmente',
          })
        }
      }, 20000)
      
      await update.downloadAndInstall((event) => {
        switch (event.event) {
          case 'Started':
            contentLength = event.data.contentLength
            downloaded = 0
            downloadStarted = true
            break
          
          case 'Progress':
            downloaded += event.data.chunkLength
            if (contentLength > 0) {
              const percent = Math.floor((downloaded / contentLength) * 100)
              updateProgress(percent)
            }
            break
          
          case 'Finished':
            clearTimeout(timeoutId)
            showInstallMessage()
            break
        }
      })
      
      // Relaunch application
      await relaunch()
    } catch (error) {
      console.error('Updater error:', error)
      showUpdateError('No se pudo completar la actualización. Verificá tu conexión e intentá nuevamente.')
    }
  }
  
  return { checkForUpdates }
}

Usage in Components

import { useUpdater } from './hooks/useUpdater'

function App() {
  const { checkForUpdates } = useUpdater()
  
  useEffect(() => {
    // Check for updates on app startup
    checkForUpdates()
  }, [])
  
  return (
    <button onClick={checkForUpdates}>
      Check for Updates
    </button>
  )
}

Update Events

The downloadAndInstall callback receives events:
EventDescriptionData
StartedDownload started{ contentLength: number }
ProgressDownload progress{ chunkLength: number }
FinishedDownload complete{}

Update Artifacts

Generating Update Files

From src-tauri/tauri.conf.json:15:
"createUpdaterArtifacts": true
When building, Tauri automatically creates:
src-tauri/target/release/bundle/msi/
├── Mas Agua_1.0.5_x64_en-US.msi
├── Mas Agua_1.0.5_x64_en-US.msi.zip       # Update bundle
└── Mas Agua_1.0.5_x64_en-US.msi.zip.sig   # Signature

Update Manifest (latest.json)

Create latest.json for each release:
{
  "version": "1.0.5",
  "notes": "Bug fixes and performance improvements",
  "pub_date": "2026-03-04T10:00:00Z",
  "platforms": {
    "windows-x86_64": {
      "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldSTmtwUUE4a2lhenBraVNOd2cwOU1ZbkxWdVJTU0lEbUZiTkp0VTFRenhtdndVZ1VwUlQ4OG0K",
      "url": "https://github.com/CspmIT/mas-agua-front/releases/download/v1.0.5/Mas.Agua_1.0.5_x64_en-US.msi.zip"
    },
    "darwin-x86_64": {
      "signature": "...",
      "url": "https://github.com/CspmIT/mas-agua-front/releases/download/v1.0.5/Mas.Agua.app.tar.gz"
    },
    "darwin-aarch64": {
      "signature": "...",
      "url": "https://github.com/CspmIT/mas-agua-front/releases/download/v1.0.5/Mas.Agua_aarch64.app.tar.gz"
    },
    "linux-x86_64": {
      "signature": "...",
      "url": "https://github.com/CspmIT/mas-agua-front/releases/download/v1.0.5/mas-agua_1.0.5_amd64.AppImage.tar.gz"
    }
  }
}

Code Signing

Generate Signing Keys

# Install Tauri CLI globally (if not already)
npm install -g @tauri-apps/cli

# Generate key pair
tauri signer generate -- -w ~/.tauri/masagua.key
This creates:
  • Private key: ~/.tauri/masagua.key (keep secret!)
  • Public key: Printed to console (add to tauri.conf.json)
NEVER commit the private key to version control. Store it securely (e.g., GitHub Secrets, password manager).

Sign Update Bundles

# Sign a file
tauri signer sign ~/.tauri/masagua.key path/to/update-bundle.zip

# Creates: update-bundle.zip.sig

Update Public Key in Config

Copy the public key output and add to tauri.conf.json:
{
  "plugins": {
    "updater": {
      "pubkey": "YOUR_PUBLIC_KEY_HERE"
    }
  }
}

GitHub Releases Workflow

Manual Release Process

  1. Build for all platforms:
# On each platform (Windows, macOS, Linux)
npm run tauri build
  1. Create GitHub Release:
gh release create v1.0.5 \
  --title "v1.0.5" \
  --notes "Release notes here"
  1. Upload artifacts:
# Upload all bundles and signatures
gh release upload v1.0.5 \
  src-tauri/target/release/bundle/**/*.{zip,tar.gz,sig}
  1. Create and upload latest.json:
gh release upload v1.0.5 latest.json

Automated CI/CD

name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18
      
      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
      
      - name: Install dependencies (Linux)
        if: matrix.os == 'ubuntu-latest'
        run: |
          sudo apt-get update
          sudo apt-get install -y libwebkit2gtk-4.1-dev \
            build-essential curl wget file libxdo-dev libssl-dev \
            libayatana-appindicator3-dev librsvg2-dev
      
      - name: Install Node dependencies
        run: npm install
      
      - name: Build Tauri app
        run: npm run tauri build
        env:
          TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
          TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
      
      - name: Upload to Release
        uses: softprops/action-gh-release@v1
        with:
          files: src-tauri/target/release/bundle/**/*.{zip,tar.gz,sig,msi,dmg,deb,rpm,AppImage}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  
  create-manifest:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Generate latest.json
        run: |
          # Script to generate latest.json from uploaded artifacts
          # Upload to release

Update Channels

Multiple Update Tracks

Support stable and beta channels:
{
  "plugins": {
    "updater": {
      "endpoints": [
        "https://github.com/CspmIT/mas-agua-front/releases/latest/download/latest.json",
        "https://github.com/CspmIT/mas-agua-front/releases/download/beta/latest.json"
      ]
    }
  }
}
Switch channels dynamically:
import { check } from '@tauri-apps/plugin-updater'

const checkBetaUpdates = async () => {
  const update = await check({
    endpoints: ['https://github.com/.../beta/latest.json']
  })
}

Troubleshooting

Updates Not Detected

  1. Verify latest.json is accessible:
curl https://github.com/CspmIT/mas-agua-front/releases/latest/download/latest.json
  1. Check version format: Use semantic versioning (1.0.5, not v1.0.5)
  2. Inspect console logs: Open DevTools in development mode

Signature Verification Failed

Error: Invalid signature
  • Ensure public key in tauri.conf.json matches private key used for signing
  • Verify .sig file uploaded alongside update bundle
  • Re-sign bundles if keys were regenerated

Download Timeout

From src/hooks/useUpdater.js:29-37, timeout is 20 seconds:
const timeoutId = setTimeout(() => {
  if (!downloadStarted) {
    Swal.fire({
      icon: 'error',
      title: 'No se pudo descargar la actualización',
      text: 'Intenta nuevamente o descárgala manualmente',
    })
  }
}, 20000)
Increase timeout for slower connections:
const TIMEOUT_MS = 60000 // 60 seconds

Manual Update Installation

If auto-update fails, users can download manually:
  1. Visit GitHub Releases
  2. Download installer for their platform
  3. Run installer to upgrade

Best Practices

  • Use semantic versioning: MAJOR.MINOR.PATCH
  • Increment MAJOR for breaking changes
  • Increment MINOR for new features
  • Increment PATCH for bug fixes
  • Example: 1.0.51.1.0 (new feature)
  • Write clear, user-friendly release notes
  • Highlight breaking changes prominently
  • Group changes by category (Features, Fixes, etc.)
  • Include migration instructions if needed
  • Test update process on all platforms before release
  • Verify signature validation works
  • Test rollback if update fails
  • Monitor error rates after release
  • Keep previous version artifacts available
  • Update latest.json to point to previous version if critical bug found
  • Communicate rollback to users via release notes

Next Steps

Building

Learn how to build production releases

Desktop Overview

Understand desktop architecture

Build docs developers (and LLMs) love