Extension Development
Extension Examples
Real-world extension implementations and use cases
Extension Examples
Learn from real examples
These production-ready extension implementations demonstrate best practices and common patterns using the VoltAPI.
Password Generator
A secure password generator with multiple modes:
// Password Generator Extension
// Trigger: "pass", "password", "pwd"
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 = ['pass', 'password', 'pwd'];
const CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&\*';
function generatePassword(length: number): string {
const array = new Uint32Array(length);
crypto.getRandomValues(array);
return Array.from(array, (num) => CHARSET[num % CHARSET.length]).join('');
}
function calculateStrength(length: number): string {
if (length >= 20) return 'Very Strong';
if (length >= 16) return 'Strong';
if (length >= 12) return 'Good';
return 'Weak';
}
class PasswordGeneratorPlugin implements Plugin {
id = 'password-generator';
name = 'Password Generator';
description = 'Generate cryptographically secure passwords';
enabled = true;
canHandle(context: PluginContext): boolean {
const query = context.query.toLowerCase().trim();
return TRIGGERS.some(trigger => query.startsWith(trigger));
}
match(context: PluginContext): PluginResult[] {
const { PluginResultType } = window.VoltAPI.types;
const query = context.query.toLowerCase().trim();
// Parse length from query (e.g., "pass 20")
const parts = query.split(/\s+/);
const lengthArg = parts.find(p => /^\d+$/.test(p));
const length = lengthArg ? Math.min(128, Math.max(8, parseInt(lengthArg))) : 16;
const password = generatePassword(length);
const strength = calculateStrength(length);
return [{
id: 'password',
type: PluginResultType.Password,
title: password,
subtitle: `${length} chars • ${strength} • Enter to copy`,
icon: '🔐',
score: 100,
data: { password, length }
}];
}
async execute(result: PluginResult): Promise<void> {
const password = result.data?.password as string;
const success = await window.VoltAPI.utils.copyToClipboard(password);
if (success) {
window.VoltAPI.notify('Password copied!', 'success');
} else {
window.VoltAPI.notify('Failed to copy', 'error');
}
}
}
export default PasswordGeneratorPlugin;{
"id": "password-generator",
"name": "Password Generator",
"version": "1.0.0",
"description": "Generate cryptographically secure passwords",
"author": { "name": "Volt Community" },
"main": "index.ts",
"category": "utilities",
"keywords": ["password", "security", "generator"],
"minVoltVersion": "0.4.0",
"permissions": ["clipboard"]
}Usage:
pass→ 16-character passwordpass 24→ 24-character passwordpassword 32→ 32-character password
Web Search
Search multiple search engines:
// Web Search Extension
// Trigger: "?", "search ", "web "
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;
}
interface PluginResult {
id: string;
type: any;
title: string;
subtitle?: string;
icon?: string;
score: number;
data?: Record<string, unknown>;
}
const TRIGGERS = ['?', 'search ', 'web ', 'google ', 'bing '];
const SEARCH_ENGINES = [
{ id: 'google', name: 'Google', url: 'https://google.com/search?q=', icon: '🔍' },
{ id: 'duckduckgo', name: 'DuckDuckGo', url: 'https://duckduckgo.com/?q=', icon: '🦆' },
{ id: 'bing', name: 'Bing', url: 'https://bing.com/search?q=', icon: '🅱️' },
];
class WebSearchPlugin implements Plugin {
id = 'web-search';
name = 'Web Search';
description = 'Search the web with various search engines';
enabled = true;
canHandle(context: PluginContext): boolean {
const query = context.query.toLowerCase();
return TRIGGERS.some(t => query.startsWith(t));
}
match(context: PluginContext): PluginResult[] {
const { PluginResultType } = window.VoltAPI.types;
// Extract search query
let searchQuery = context.query;
for (const trigger of TRIGGERS) {
if (searchQuery.toLowerCase().startsWith(trigger)) {
searchQuery = searchQuery.slice(trigger.length).trim();
break;
}
}
if (!searchQuery) {
return [{
id: 'hint',
type: PluginResultType.Info,
title: 'Type your search query',
subtitle: 'Example: ? what is volt launcher',
icon: '💡',
score: 50
}];
}
return SEARCH_ENGINES.map((engine, i) => ({
id: engine.id,
type: PluginResultType.WebSearch,
title: `Search "${searchQuery}"`,
subtitle: `Open in ${engine.name}`,
icon: engine.icon,
score: 100 - i,
data: {
url: engine.url + encodeURIComponent(searchQuery),
engine: engine.name
}
}));
}
async execute(result: PluginResult): Promise<void> {
const url = result.data?.url as string;
if (url) {
await window.VoltAPI.utils.openUrl(url);
}
}
}
export default WebSearchPlugin;{
"id": "web-search",
"name": "Web Search",
"version": "1.0.0",
"description": "Search the web with various search engines",
"author": { "name": "Volt Community" },
"main": "index.ts",
"category": "utilities",
"keywords": ["search", "web", "google", "bing"],
"minVoltVersion": "0.4.0",
"permissions": ["network"]
}Usage:
?what is typescript→ Search all enginessearch weather→ Search for weathergoogle react docs→ Search Google
Calculator
Evaluate mathematical expressions:
// Calculator Extension
// Trigger: Mathematical expressions
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;
}
interface PluginResult {
id: string;
type: any;
title: string;
subtitle?: string;
icon?: string;
score: number;
data?: Record<string, unknown>;
}
// Simple math expression regex
const MATH_REGEX = /^[\d\s+\-*/().,%^]+$/;
function evaluate(expression: string): number {
// Remove spaces and replace common symbols
const cleaned = expression
.replace(/\s/g, '')
.replace(/,/g, '')
.replace(/%/g, '/100')
.replace(/\^/g, '\*\*');
// Use Function constructor for safe evaluation
// Only allows mathematical operations
const fn = new Function(`return (${cleaned})`);
return fn();
}
function formatResult(num: number): string {
if (Number.isInteger(num)) {
return num.toLocaleString();
}
// Round to 10 decimal places to avoid floating point issues
return parseFloat(num.toFixed(10)).toLocaleString(undefined, {
maximumFractionDigits: 10
});
}
class CalculatorPlugin implements Plugin {
id = 'calculator';
name = 'Calculator';
description = 'Evaluate mathematical expressions';
enabled = true;
canHandle(context: PluginContext): boolean {
const query = context.query.trim();
// Must contain at least one digit and one operator
return MATH_REGEX.test(query) &&
/\d/.test(query) &&
/[+\-*/.^%]/.test(query);
}
match(context: PluginContext): PluginResult[] {
const { PluginResultType } = window.VoltAPI.types;
const query = context.query.trim();
try {
const result = evaluate(query);
if (!isFinite(result)) {
return [{
id: 'error',
type: PluginResultType.Calculator,
title: 'Invalid calculation',
subtitle: 'Division by zero or invalid expression',
icon: '⚠️',
score: 50
}];
}
const formatted = formatResult(result);
return [{
id: 'result',
type: PluginResultType.Calculator,
title: formatted,
subtitle: `${query} = ${formatted} • Enter to copy`,
icon: '🔢',
score: 100,
data: { result: formatted, expression: query }
}];
} catch (error) {
return [];
}
}
async execute(result: PluginResult): Promise<void> {
const value = result.data?.result as string;
if (value) {
const success = await window.VoltAPI.utils.copyToClipboard(value);
if (success) {
window.VoltAPI.notify('Result copied!', 'success');
}
}
}
}
export default CalculatorPlugin;{
"id": "calculator",
"name": "Calculator",
"version": "1.0.0",
"description": "Evaluate mathematical expressions",
"author": { "name": "Volt Community" },
"main": "index.ts",
"category": "utilities",
"keywords": ["calculator", "math", "compute"],
"minVoltVersion": "0.4.0",
"permissions": ["clipboard"]
}Usage:
2 + 2→ 4100 * 1.15→ 115(50 + 25) / 3→ 252^10→ 1,024
Timer
Create timers with notifications:
// Timer Extension
// Trigger: "timer", "remind"
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;
}
interface PluginResult {
id: string;
type: any;
title: string;
subtitle?: string;
icon?: string;
score: number;
data?: Record<string, unknown>;
}
const TIME_REGEX = /^(?:timer|remind)\s+(\d+)\s\*(s|sec|seconds?|m|min|minutes?|h|hours?)?$/i;
function parseTime(amount: number, unit: string): number {
const u = (unit || 's').toLowerCase();
if (u.startsWith('h')) return amount _ 3600;
if (u.startsWith('m')) return amount _ 60;
return amount;
}
function formatDuration(seconds: number): string {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;
const parts = [];
if (h > 0) parts.push(`${h}h`);
if (m > 0) parts.push(`${m}m`);
if (s > 0 || parts.length === 0) parts.push(`${s}s`);
return parts.join(' ');
}
class TimerPlugin implements Plugin {
id = 'timer';
name = 'Timer';
description = 'Create timers and reminders';
enabled = true;
canHandle(context: PluginContext): boolean {
const query = context.query.toLowerCase().trim();
return query.startsWith('timer') || query.startsWith('remind');
}
match(context: PluginContext): PluginResult[] {
const { PluginResultType } = window.VoltAPI.types;
const query = context.query.trim();
const match = TIME_REGEX.exec(query);
if (!match) {
return [{
id: 'hint',
type: PluginResultType.Timer,
title: 'Set a timer',
subtitle: 'Example: timer 5m, timer 30s, timer 1h',
icon: '⏱️',
score: 50
}];
}
const [, amountStr, unit] = match;
const amount = parseInt(amountStr);
const seconds = parseTime(amount, unit);
const formatted = formatDuration(seconds);
return [{
id: 'timer',
type: PluginResultType.Timer,
title: `Set ${formatted} timer`,
subtitle: 'Press Enter to start',
icon: '⏱️',
score: 100,
data: { seconds, display: formatted }
}];
}
async execute(result: PluginResult): Promise<void> {
const seconds = result.data?.seconds as number;
const display = result.data?.display as string;
if (!seconds) return;
window.VoltAPI.notify(`Timer set for ${display}`, 'success');
// Start the timer
setTimeout(() => {
// Show notification when timer completes
if ('Notification' in window && Notification.permission === 'granted') {
new Notification('Timer Complete!', {
body: `Your ${display} timer has finished`,
icon: '⏱️'
});
}
window.VoltAPI.notify(`Timer complete! (${display})`, 'info');
}, seconds * 1000);
}
}
export default TimerPlugin;{
"id": "timer",
"name": "Timer",
"version": "1.0.0",
"description": "Create timers and reminders",
"author": { "name": "Volt Community" },
"main": "index.ts",
"category": "utilities",
"keywords": ["timer", "reminder", "countdown"],
"minVoltVersion": "0.4.0",
"permissions": ["notifications"]
}Usage:
timer 30s→ 30 second timertimer 5m→ 5 minute timertimer 1h→ 1 hour timer
UUID Generator
Generate unique identifiers:
// UUID Generator Extension
// Trigger: "uuid", "guid"
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;
}
interface PluginResult {
id: string;
type: any;
title: string;
subtitle?: string;
icon?: string;
score: number;
data?: Record<string, unknown>;
}
function generateUUID(): string {
// Use crypto.randomUUID if available (modern browsers)
if (typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
// Fallback implementation
const array = new Uint8Array(16);
crypto.getRandomValues(array);
// Set version (4) and variant (10xx)
array[6] = (array[6] & 0x0f) | 0x40;
array[8] = (array[8] & 0x3f) | 0x80;
const hex = Array.from(array, b => b.toString(16).padStart(2, '0')).join('');
return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`;
}
class UUIDPlugin implements Plugin {
id = 'uuid-generator';
name = 'UUID Generator';
description = 'Generate unique identifiers';
enabled = true;
canHandle(context: PluginContext): boolean {
const query = context.query.toLowerCase().trim();
return query === 'uuid' || query === 'guid' || query.startsWith('uuid ');
}
match(context: PluginContext): PluginResult[] {
const { PluginResultType } = window.VoltAPI.types;
const query = context.query.toLowerCase().trim();
// Check if user wants multiple UUIDs
const countMatch = query.match(/^uuid\s+(\d+)$/);
const count = countMatch ? Math.min(10, parseInt(countMatch[1])) : 1;
const results: PluginResult[] = [];
for (let i = 0; i < count; i++) {
const uuid = generateUUID();
results.push({
id: `uuid-${i}`,
type: PluginResultType.Info,
title: uuid,
subtitle: 'Press Enter to copy',
icon: '🔑',
score: 100 - i,
data: { uuid }
});
}
return results;
}
async execute(result: PluginResult): Promise<void> {
const uuid = result.data?.uuid as string;
if (uuid) {
const success = await window.VoltAPI.utils.copyToClipboard(uuid);
if (success) {
window.VoltAPI.notify('UUID copied!', 'success');
}
}
}
}
export default UUIDPlugin;{
"id": "uuid-generator",
"name": "UUID Generator",
"version": "1.0.0",
"description": "Generate unique identifiers",
"author": { "name": "Volt Community" },
"main": "index.ts",
"category": "development",
"keywords": ["uuid", "guid", "unique", "id"],
"minVoltVersion": "0.4.0",
"permissions": ["clipboard"]
}Usage:
uuid→ Generate one UUIDuuid 5→ Generate 5 UUIDs
Backend Plugin Example (Rust)
For system-level integrations, use Rust backend plugins:
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize)]
pub struct GameInfo {
pub id: String,
pub name: String,
pub path: PathBuf,
pub icon: Option<String>,
}
pub struct SteamPlugin {
steam_path: PathBuf,
}
impl SteamPlugin {
pub fn new() -> Self {
let steam_path = Self::find_steam_path();
Self { steam_path }
}
fn find_steam_path() -> PathBuf {
#[cfg(target_os = "windows")]
{ PathBuf::from("C:\\Program Files (x86)\\Steam") }
#[cfg(target_os = "macos")]
{ PathBuf::from("/Users/Shared/Steam") }
#[cfg(target_os = "linux")]
{ PathBuf::from("~/.steam/steam") }
}
pub fn scan_games(&self) -> Vec<GameInfo> {
let library_path = self.steam_path.join("steamapps");
let mut games = Vec::new();
if let Ok(entries) = std::fs::read_dir(&library_path) {
for entry in entries.flatten() {
if let Some(name) = entry.file_name().to_str() {
if name.starts_with("appmanifest_") && name.ends_with(".acf") {
if let Ok(game) = self.parse_manifest(&entry.path()) {
games.push(game);
}
}
}
}
}
games
}
fn parse_manifest(&self, path: &PathBuf) -> Result<GameInfo, Box<dyn std::error::Error>> {
let content = std::fs::read_to_string(path)?;
let id = Self::extract_value(&content, "appid")?;
let name = Self::extract_value(&content, "name")?;
let install_dir = Self::extract_value(&content, "installdir")?;
Ok(GameInfo {
id,
name,
path: self.steam_path.join("steamapps/common").join(&install_dir),
icon: None,
})
}
fn extract_value(content: &str, key: &str) -> Result<String, Box<dyn std::error::Error>> {
let pattern = format!("\"{}\"\\s+\"([^\"]+)\"", key);
let re = regex::Regex::new(&pattern)?;
re.captures(content)
.and_then(|c| c.get(1))
.map(|m| m.as_str().to_string())
.ok_or_else(|| "Key not found".into())
}
}
// Tauri command to expose to frontend
#[tauri::command]
pub async fn scan_steam_games() -> Result<Vec<GameInfo>, String> {
let plugin = SteamPlugin::new();
Ok(plugin.scan_games())
}