Volt LogoVolt
Extension Development

Développement d'extensions

Apprenez à créer des extensions pour étendre les fonctionnalités de Volt

Guide de développement d'extensions

Créez des extensions puissantes pour Volt

Créez des extensions qui s'intègrent parfaitement à l'architecture ultra-rapide de Volt. Les extensions sont distribuées sous forme de fichiers ZIP et peuvent être partagées via le registre officiel.

Bienvenue dans le guide de développement d'extensions de Volt ! Ce guide vous aidera à créer vos propres extensions pour étendre les capacités de Volt.

Modèle de sécurité

Les extensions communautaires s'exécutent dans un sandbox Web Worker avec une CSP stricte. eval, XMLHttpRequest, WebSocket et l'accès DOM direct sont bloqués. Les appels réseau passent par un proxy gardé par permissions. Consultez Sandbox & permissions avant de publier.

SDK et CLI

Installez le SDK officiel et l'outil CLI pour commencer :

npm install @voltlaunchrr/plugin-api
npm install -g @voltlaunchrr/plugin-cli
bun add @voltlaunchrr/plugin-api
bun add -g @voltlaunchrr/plugin-cli
pnpm add @voltlaunchrr/plugin-api
pnpm add -g @voltlaunchrr/plugin-cli

Le CLI fournit scaffolding, validation et packaging :

volt-plugin init my-extension    # Créer une nouvelle extension
volt-plugin test                 # Valider le manifeste, l'interface et les types
volt-plugin publish              # Empaqueter et générer l'entrée du registre

Démarrage rapide

Créez le répertoire de l'extension

Utilisez le CLI ou créez manuellement :

volt-plugin init my-extension
cd my-extension
manifest.json
index.ts

Créez manifest.json

Chaque extension requiert un fichier manifeste :

manifest.json
{
  "id": "my-extension",
  "name": "My Extension",
  "version": "1.0.0",
  "description": "Une extension Volt personnalisée",
  "author": { "name": "Votre nom" },
  "main": "index.ts",
  "category": "utilities",
  "minVoltVersion": "0.4.0",
  "permissions": []
}

Implémentez votre plugin

Créez le fichier principal du plugin :

index.ts
class MyExtensionPlugin implements Plugin {
  id = 'my-extension';
  name = 'My Extension';
  description = 'Une extension Volt personnalisée';
  enabled = true;

  canHandle(context: PluginContext): boolean {
    return context.query.toLowerCase().startsWith('my ');
  }

  match(context: PluginContext): PluginResult[] {
    const { PluginResultType } = window.VoltAPI.types;
    const query = context.query.slice(3); // Retire "my "

    return [{
      id: '1',
      type: PluginResultType.Info,
      title: `Process: ${query}`,
      subtitle: 'Appuyez sur Entrée pour exécuter',
      icon: '⚡',
      score: 100,
      data: { query }
    }];
  }

  async execute(result: PluginResult): Promise<void> {
    window.VoltAPI.notify(`Exécuté avec : ${result.data?.query}`, 'success');
  }
}

export default MyExtensionPlugin;

Testez votre extension (mode dev)

  1. Ouvrez Volt → ParamètresExtensions
  2. Cliquez sur « Lier une extension de dev »
  3. Sélectionnez le dossier de votre extension
  4. Tapez votre mot-clé déclencheur pour tester !

Rechargement à chaud

Modifiez votre code, sauvegardez, et appuyez sur Ctrl+R pour rafraîchir. Aucun packaging requis !

Voir Workflow de développement pour plus d'options.

Architecture des extensions

Volt propose un système d'extensions hybride avec deux couches :

Extensions frontend

TypeScript — Gèrent l'UI et les interactions utilisateur. Idéales pour calculatrices, recherches web, générateurs.

Plugins backend

Rust — Gèrent les intégrations système. Idéals pour scanners de jeux, moniteurs système, opérations fichiers.

Extensions frontend

  • Écrites en TypeScript
  • S'exécutent dans le contexte navigateur
  • Accès à window.VoltAPI pour les utilitaires
  • Timeout de 500 ms par requête
  • Idéales pour : calculatrices, recherches web, générateurs, convertisseurs
class MyPlugin implements Plugin {
  id = 'my-plugin';
  name = 'My Plugin';
  description = 'Fait quelque chose d\'utile';
  enabled = true;

  canHandle(context: PluginContext): boolean {
    return context.query.startsWith('my ');
  }

  match(context: PluginContext): PluginResult[] {
    const { PluginResultType } = window.VoltAPI.types;
    return [{
      id: '1',
      type: PluginResultType.Info,
      title: 'Résultat',
      score: 100
    }];
  }

  async execute(result: PluginResult): Promise<void> {
    await window.VoltAPI.utils.copyToClipboard('copié !');
    window.VoltAPI.notify('Terminé !', 'success');
  }
}

export default MyPlugin;

Plugins backend

  • Écrits en Rust
  • Accès système complet
  • Performance native
  • Idéals pour : scanners de jeux, moniteurs système, opérations fichiers
use async_trait::async_trait;
use crate::core::traits::Plugin;

pub struct MyBackendPlugin {
    enabled: bool,
}

#[async_trait]
impl Plugin for MyBackendPlugin {
    fn id(&self) -> &str { "my-backend-plugin" }
    fn name(&self) -> &str { "My Backend Plugin" }
    fn description(&self) -> &str { "Intégration système" }
    fn is_enabled(&self) -> bool { self.enabled }
    fn required_capabilities(&self) -> Vec<String> { vec![] }
    
    async fn initialize(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        Ok(())
    }
    
    async fn shutdown(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        Ok(())
    }
}

Diagramme d'architecture

┌─────────────────────────────────────────────────────────┐
│              Frontend (React/TypeScript)                │
│  ┌───────────────────────────────────────────────────┐  │
│  │              Extension Loader                      │  │
│  │  • Charge les extensions depuis ZIP ou dossiers   │  │
│  │  • Compile TypeScript → JavaScript                │  │
│  │  • Injecte VoltAPI                                │  │
│  └───────────────────────────────────────────────────┘  │
│              ↓                                          │
│  ┌───────────────────────────────────────────────────┐  │
│  │              Plugin Registry                       │  │
│  │  • Gère tous les plugins (intégrés + extensions)  │  │
│  │  • Route les requêtes vers les plugins            │  │
│  │  • Gère les timeouts de 500 ms                    │  │
│  └───────────────────────────────────────────────────┘  │
│              ↓                                          │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │ Plugin  │  │Extension│  │Extension│  │  DEV    │   │
│  │ intégré │  │    A    │  │    B    │  │Extension│   │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘   │
└─────────────────────────────────────────────────────────┘
                    ↕ Tauri IPC
┌─────────────────────────────────────────────────────────┐
│               Backend (Rust/Tauri)                      │
│  ┌───────────────────────────────────────────────────┐  │
│  │         Commandes de gestion d'extensions          │  │
│  │  • install_extension() / uninstall_extension()    │  │
│  │  • link_dev_extension() / unlink_dev_extension()  │  │
│  │  • toggle_extension() / refresh_dev_extension()   │  │
│  │  • fetch_extension_registry()                     │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

VoltAPI — API globale

Toutes les extensions ont accès à l'objet global window.VoltAPI :

// Types
window.VoltAPI.types.PluginResultType; // Enum des types de résultat

// Utilitaires
window.VoltAPI.utils.copyToClipboard(text); // Copier dans le presse-papiers
window.VoltAPI.utils.openUrl(url); // Ouvrir une URL dans le navigateur
window.VoltAPI.utils.fuzzyScore(query, str); // Correspondance floue
window.VoltAPI.utils.formatNumber(num); // Formater des nombres

// Communication backend
window.VoltAPI.invoke(command, args); // Appeler des commandes Tauri

// Événements
window.VoltAPI.events.emit(event, data); // Émettre un événement personnalisé
window.VoltAPI.events.on(event, handler); // S'abonner aux événements

// Notifications
window.VoltAPI.notify(message, type); // Afficher une notification

Référence complète de l'API

Voir la Référence API pour la documentation complète de VoltAPI.

Types de résultats de plugin

Les extensions peuvent renvoyer différents types de résultats :

Prop

Type

Distribution d'extensions

Les extensions sont distribuées sous forme de fichiers ZIP via GitHub Releases :

  1. Empaquetez les fichiers de votre extension dans un ZIP
  2. Créez une GitHub Release avec le ZIP en asset
  3. Soumettez au registre officiel pour la découvrabilité
my-extension-v1.0.0.zip
├── manifest.json
├── index.ts
├── types.ts
└── utils/
    └── helpers.ts

Voir le Guide de publication pour des instructions détaillées.

Exemple complet

Voici une extension complète, prête pour la production :

index.ts
// Extension Greeting
// Répond aux requêtes "hello" avec des salutations personnalisées

interface Plugin {
  id: string;
  name: string;
  description: string;
  enabled: boolean;
  canHandle(context: PluginContext): boolean;
  match(context: PluginContext): PluginResult[];
  execute(result: PluginResult): Promise<void>;
}

interface PluginContext {
  query: string;
  settings?: Record<string, unknown>;
}

interface PluginResult {
  id: string;
  type: any;
  title: string;
  subtitle?: string;
  icon?: string;
  score: number;
  data?: Record<string, unknown>;
}

const TRIGGERS = ["hello", "hi", "hey", "greet"];

class GreetingPlugin implements Plugin {
  id = "greeting";
  name = "Greeting";
  description = "Salutations amicales pour tous";
  enabled = true;

  canHandle(context: PluginContext): boolean {
    const query = context.query.toLowerCase().trim();
    return TRIGGERS.some((t) => query.startsWith(t));
  }

  match(context: PluginContext): PluginResult[] {
    const { PluginResultType } = window.VoltAPI.types;
    const query = context.query.trim();

    // Extraire le nom s'il est fourni (ex. "hello John")
    const parts = query.split(/\s+/);
    const name = parts.length > 1 ? parts.slice(1).join(" ") : "friend";

    const greetings = [`Hello, ${name}! 👋`, `Hey there, ${name}! ✨`, `Greetings, ${name}! 🌟`];

    return greetings.map((greeting, i) => ({
      id: `greeting-${i}`,
      type: PluginResultType.Info,
      title: greeting,
      subtitle: "Appuyez sur Entrée pour copier",
      icon: "👋",
      score: 100 - i,
      data: { greeting },
    }));
  }

  async execute(result: PluginResult): Promise<void> {
    const greeting = result.data?.greeting as string;
    const success = await window.VoltAPI.utils.copyToClipboard(greeting);

    if (success) {
      window.VoltAPI.notify("Salutation copiée !", "success");
    }
  }
}

export default GreetingPlugin;
manifest.json
{
  "id": "greeting",
  "name": "Greeting",
  "version": "1.0.0",
  "description": "Salutations amicales pour tous",
  "author": { "name": "Votre nom" },
  "main": "index.ts",
  "category": "utilities",
  "keywords": ["hello", "greeting", "friendly"],
  "minVoltVersion": "0.4.0",
  "permissions": ["clipboard"]
}

Étapes suivantes

On this page