Managing Profiles in Clash Nyanpasu: Create, Update, Delete, and Import Guide
Managing profiles in Clash Nyanpasu involves TypeScript wrappers that invoke Rust backend commands through Tauri's IPC layer to create, update, delete, and import YAML, JavaScript, or Lua configuration files.
Managing profiles in Clash Nyanpasu is orchestrated through a multi-layered architecture that connects the React frontend to the Rust backend via Tauri commands. The libnyanpasu/clash-nyanpasu repository implements this workflow through the @nyanpasu/interface package, which exposes type-safe hooks and service functions that ultimately invoke native commands defined in src-tauri/src/commands/profile.rs.
Architecture of Profile Management in Clash Nyanpasu
The profile management system spans four distinct layers, each with specific responsibilities for handling Clash configuration files.
Frontend UI Layer
The user interface components display profile lists and handle import dialogs. Key implementation files include:
frontend/nyanpasu/src/pages/(main)/main/profiles/_modules/profiles-navigate.tsx– Renders the profile navigation and countsfrontend/nyanpasu/src/pages/(main)/main/profiles/_modules/profile-quick-import.tsx– Handles the quick import dialog for remote URLs
React Hooks and State Management
The useProfile hook, exported from @nyanpasu/interface, maintains the profile collection in a TanStack Router query cache. This hook automatically invalidates and refreshes when mutations occur.
Tauri IPC Bridge
TypeScript wrappers in frontend/interface/src/service/tauri.ts provide thin abstractions over native Tauri commands, while frontend/interface/src/ipc/bindings.ts implements the low-level TAURI_INVOKE helpers. These layers handle serialization and type safety before invoking the Rust backend.
Rust Backend Implementation
The actual file operations occur in src-tauri/src/commands/profile.rs, which implements commands for creating, updating, deleting, and importing profiles while managing the profiles/ directory and runtime configuration.
Profile Management API Commands
The TypeScript service layer exposes specific functions for managing profiles in Clash Nyanpasu through the Tauri command interface.
Creating New Profiles
The createProfile function initializes a new profile entry and optionally writes initial file data.
export const createProfile = async (item, fileData?) =>
invoke<void>('create_profile', { item, fileData })
The item parameter accepts a partial Profile object containing fields like type, name, and uid. The optional fileData parameter holds raw content for script-type profiles (JavaScript or Lua).
Updating Existing Profiles
Two functions handle modifications to existing profiles:
updateProfile– Full updates with optional remote import optionspatchProfile– Partial updates modifying only specified fields
export const updateProfile = async (uid, option?) =>
invoke<void>('update_profile', { uid, option })
async patchProfile(uid, profile) // Partial update implementation
The option parameter uses RemoteProfileOptionsBuilder for configuring merge behavior during remote updates.
Deleting Profiles
The deleteProfile function removes a profile from the internal store and deletes its associated file from disk.
export const deleteProfile = async (uid) =>
invoke<void>('delete_profile', { uid })
Importing Remote Profiles
The importProfile function downloads configuration files from remote URLs and integrates them into the local profile collection.
export const importProfile = async (url, option) =>
invoke<void>('import_profile', { url, option })
The option parameter supports specifying merge behavior and script types (JavaScript or Lua) for non-YAML configurations.
Reordering Profiles
Two functions manage profile ordering for drag-and-drop interfaces:
reorderProfile(activeId, overId) // Swap two specific profiles
reorderProfilesByList(list) // Apply a complete ordering
Implementation Examples for Managing Profiles
The following example demonstrates the complete workflow for managing profiles in Clash Nyanpasu using the TypeScript API:
import {
createProfile,
updateProfile,
deleteProfile,
importProfile,
} from '@nyanpasu/interface';
// ------------------------------------------------
// 1. Create a brand-new static profile
// ------------------------------------------------
await createProfile(
{
uid: 'my-static-profile',
type: 'Profile', // plain YAML profile
name: 'My Static Profile',
// other fields like 'proxy' or 'rules' can be added here
},
null // no extra script data
);
// ------------------------------------------------
// 2. Update the name of an existing profile
// ------------------------------------------------
await updateProfile('my-static-profile', {
name: 'Renamed Profile',
});
// ------------------------------------------------
// 3. Delete a profile (removes the file from disk)
// ------------------------------------------------
await deleteProfile('my-static-profile');
// ------------------------------------------------
// 4. Import a remote profile (URL can be a raw YAML or a script)
// ------------------------------------------------
await importProfile('https://raw.githubusercontent.com/example/proxy.yaml', {
// RemoteProfileOptionsBuilder – optional flags
merge: false, // treat as a separate profile
script_type: 'JavaScript', // only needed for script-type imports
});
All calls return a Promise that resolves when the native command finishes. Errors are thrown as JavaScript Error objects and can be caught with try / catch.
UI Integration and React Hooks
The frontend components consume profile data through reactive patterns that automatically synchronize with backend state.
Profile Navigation Component
The profiles-navigate.tsx module displays profile counts and handles navigation:
// File: frontend/nyanpasu/src/pages/(main)/main/profiles/_modules/profiles-navigate.tsx
import { useProfile } from '@nyanpasu/interface';
...
const { query: { data: profiles } } = useProfile(); // ← reads cache
...
// Profile counts are calculated with lodash `mapValues` and displayed
When Tauri commands invalidate the query cache, the hook automatically triggers a re-fetch, updating the UI with the latest profile list.
Quick Import Dialog
The quick import interface demonstrates direct API usage:
// File: frontend/nyanpasu/src/pages/(main)/main/profiles/_modules/profile-quick-import.tsx
import { importProfile } from '@nyanpasu/interface';
...
await importProfile(importUrl, { merge: false });
Upon successful import, the UI displays a confirmation toast and the useProfile hook refreshes the list to include the newly imported configuration.
Rust Backend Implementation
The TypeScript wrappers ultimately invoke native commands defined in src-tauri/src/commands/profile.rs:
#[tauri::command]
async fn create_profile(item: ProfileBuilder, file_data: Option<String>) -> Result<(), String> { … }
#[tauri::command]
async fn update_profile(uid: String, option: Option<RemoteProfileOptionsBuilder>) -> Result<(), String> { … }
#[tauri::command]
async fn delete_profile(uid: String) -> Result<(), String> { … }
#[tauri::command]
async fn import_profile(url: String, option: Option<RemoteProfileOptionsBuilder>) -> Result<(), String> { … }
These functions interact with the ProfileStore abstraction, which manages the local profiles/ directory. The backend handles file I/O for YAML, JavaScript, and Lua configurations, validates syntax, and notifies the runtime engine to reload the Clash configuration.
Summary
Managing profiles in Clash Nyanpasu follows a structured flow from the React frontend through Tauri IPC to the Rust backend:
- Frontend Components in
profiles-navigate.tsxandprofile-quick-import.tsxprovide the user interface for profile operations - TypeScript API in
frontend/interface/src/service/tauri.tsexposes type-safe wrappers includingcreateProfile,updateProfile,deleteProfile, andimportProfile - React Hooks like
useProfileautomatically synchronize UI state with backend changes through TanStack Router query invalidation - Rust Commands in
src-tauri/src/commands/profile.rshandle the actual file system operations, validation, and runtime configuration updates
This architecture ensures that managing profiles in Clash Nyanpasu remains type-safe, reactive, and consistent across the entire application stack.
Frequently Asked Questions
How do I create a new profile programmatically in Clash Nyanpasu?
To create a new profile programmatically, import the createProfile function from @nyanpasu/interface and invoke it with a profile configuration object containing at minimum the uid, type, and name fields. For script-based profiles, provide the raw file content as the second argument. The function returns a Promise that resolves when the Rust backend has written the file to the profiles/ directory.
What is the difference between updateProfile and patchProfile in the Clash Nyanpasu API?
The updateProfile function performs a full update operation and accepts an optional RemoteProfileOptionsBuilder for configuring merge behavior during remote imports, making it suitable for comprehensive profile modifications. In contrast, patchProfile performs a partial update where only the fields explicitly provided in the profile object are modified, leaving all other existing fields unchanged. Both functions ultimately invoke commands in src-tauri/src/commands/profile.rs to persist changes.
How does the useProfile hook handle real-time updates when profiles are modified?
The useProfile hook utilizes TanStack Router's query caching mechanism to maintain the profile list in the frontend, automatically fetching fresh data from the Rust backend when the component mounts. When mutation commands like createProfile or deleteProfile complete successfully, they trigger cache invalidation, causing the hook to re-fetch the updated profile list and re-render dependent UI components such as profiles-navigate.tsx. This reactive pattern ensures the UI remains synchronized with the filesystem state without manual refresh operations.
Can I import profiles from remote URLs that contain JavaScript or Lua scripts instead of YAML?
Yes, the importProfile function supports importing remote configurations in YAML, JavaScript, or Lua formats by specifying the appropriate script_type in the RemoteProfileOptionsBuilder options parameter. When importing a script-type profile, set script_type to 'JavaScript' or 'Lua' and the Rust backend will handle the file extension and validation accordingly. The merge option controls whether the imported profile replaces existing configurations or merges with them, providing flexibility for complex setup scenarios.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →