mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
feat: 添加 Vite web 开发模式 mock 系统
通过 Vite alias 拦截 @tauri-apps/* 导入,使用 mock 模块替代真实的 Tauri API, 使得 pnpm run dev 可以在浏览器中独立运行,无需启动 Tauri 后端。 主要变更: - 新增 src/lib/tauri-mock/ 模块化 mock 系统 - 修复 vite.config.ts 的 ES 模块 __dirname 兼容性 - 移除旧的 src/lib/tauri-mock.ts 文件 - 更新 useTauri.ts 使用静态导入 - 添加 200+ Tauri 命令的 mock 实现
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri",
|
||||
"tauri:dev": "tauri dev --config src-tauri/tauri.conf.json",
|
||||
"tauri:dev:headless": "tauri dev --config src-tauri/tauri.conf.headless.json",
|
||||
"lint": "eslint src --max-warnings 0",
|
||||
"format": "prettier --write \"src/**/*.{ts,tsx,css}\"",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// Import mock invoke directly - Vite alias will replace @tauri-apps/api/core
|
||||
// with the mock module in web mode
|
||||
import { invoke as baseInvoke } from "@tauri-apps/api/core";
|
||||
|
||||
// Safe Tauri invoke wrapper for web mode compatibility
|
||||
const safeInvoke = async (cmd: string, args?: any): Promise<any> => {
|
||||
// Check if Tauri is available via window.__TAURI__
|
||||
@@ -13,15 +17,8 @@ const safeInvoke = async (cmd: string, args?: any): Promise<any> => {
|
||||
return (window as any).__TAURI__.invoke(cmd, args);
|
||||
}
|
||||
|
||||
// Try to use real Tauri API (dynamic import)
|
||||
try {
|
||||
const { invoke } = await import("@tauri-apps/api/core");
|
||||
return invoke(cmd, args);
|
||||
} catch (_e) {
|
||||
// Not in Tauri environment, return mock data for development
|
||||
console.warn(`[useTauri] Tauri API not available for command: ${cmd}`);
|
||||
throw new Error(`Tauri API not available. Command: ${cmd}`);
|
||||
}
|
||||
// Not in Tauri environment - use the imported invoke (mock in web mode)
|
||||
return baseInvoke(cmd, args);
|
||||
};
|
||||
|
||||
export interface ServerStatus {
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/**
|
||||
* Tauri API Mock for Web Development Mode
|
||||
*
|
||||
* Provides mock implementations of Tauri APIs when running in web mode (npm run dev)
|
||||
* This allows the app to run in browser without Tauri backend
|
||||
*/
|
||||
|
||||
export const isTauriAvailable = () => {
|
||||
return typeof window !== "undefined" && "__TAURI__" in window;
|
||||
};
|
||||
|
||||
export const mockTauriAPI = () => {
|
||||
if (typeof window === "undefined") return;
|
||||
if (isTauriAvailable()) return; // Already have real Tauri
|
||||
|
||||
console.log("[Mock] Initializing Tauri API mock for web mode");
|
||||
|
||||
// Mock Tauri global
|
||||
(window as any).__TAURI__ = {
|
||||
invoke: async (cmd: string, args?: any) => {
|
||||
console.log(`[Mock] Tauri invoke: ${cmd}`, args);
|
||||
|
||||
// Return mock data based on command
|
||||
switch (cmd) {
|
||||
case "get_config":
|
||||
return {
|
||||
language: "zh",
|
||||
theme: "system",
|
||||
proxy: "",
|
||||
minimize_to_tray: false,
|
||||
launch_on_startup: false,
|
||||
tls: {
|
||||
enable: false,
|
||||
cert_path: null,
|
||||
key_path: null,
|
||||
},
|
||||
remote_management: {
|
||||
allow_remote: false,
|
||||
secret_key: null,
|
||||
disable_control_panel: false,
|
||||
},
|
||||
quota_exceeded: {
|
||||
switch_project: true,
|
||||
switch_preview_model: false,
|
||||
cooldown_seconds: 60,
|
||||
},
|
||||
};
|
||||
|
||||
case "save_config":
|
||||
console.log("[Mock] Config saved:", args);
|
||||
return { success: true };
|
||||
|
||||
case "get_providers":
|
||||
return [];
|
||||
|
||||
case "get_credentials":
|
||||
return [];
|
||||
|
||||
case "check_server_status":
|
||||
case "get_server_status":
|
||||
return {
|
||||
running: false,
|
||||
host: "127.0.0.1",
|
||||
port: 8787,
|
||||
requests: 0,
|
||||
uptime_secs: 0,
|
||||
};
|
||||
|
||||
case "start_server":
|
||||
return "Server started (mock)";
|
||||
|
||||
case "stop_server":
|
||||
return "Server stopped (mock)";
|
||||
|
||||
case "get_default_provider":
|
||||
return "openai";
|
||||
|
||||
case "set_default_provider":
|
||||
return "Provider set (mock)";
|
||||
|
||||
case "get_available_models":
|
||||
return [];
|
||||
|
||||
case "get_network_info":
|
||||
return {
|
||||
local_ip: "127.0.0.1",
|
||||
public_ip: null,
|
||||
hostname: "localhost",
|
||||
};
|
||||
|
||||
default:
|
||||
console.warn(`[Mock] Unhandled Tauri command: ${cmd}`);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
event: {
|
||||
listen: async (event: string, _handler: any) => {
|
||||
console.log(`[Mock] Tauri listen: ${event}`);
|
||||
// Return unlisten function
|
||||
return () => {
|
||||
console.log(`[Mock] Tauri unlisten: ${event}`);
|
||||
};
|
||||
},
|
||||
|
||||
emit: async (event: string, payload?: any) => {
|
||||
console.log(`[Mock] Tauri emit: ${event}`, payload);
|
||||
},
|
||||
|
||||
once: async (event: string, _handler: any) => {
|
||||
console.log(`[Mock] Tauri once: ${event}`);
|
||||
return () => {};
|
||||
},
|
||||
},
|
||||
|
||||
tauri: {
|
||||
invoke: async (cmd: string, args?: any) => {
|
||||
return (window as any).__TAURI__.invoke(cmd, args);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Mock @tauri-apps/api modules
|
||||
(window as any).__TAURI_INVOKE__ = (window as any).__TAURI__.invoke;
|
||||
|
||||
console.log("[Mock] Tauri API mock initialized");
|
||||
console.log("[Mock] Running in WEB MODE - some features may not work");
|
||||
console.log("[Mock] For full functionality, run: npm run tauri dev");
|
||||
};
|
||||
|
||||
// Auto-initialize in development mode
|
||||
if (import.meta.env.DEV && !isTauriAvailable()) {
|
||||
mockTauriAPI();
|
||||
}
|
||||
@@ -0,0 +1,668 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/api/core
|
||||
*/
|
||||
|
||||
// 模拟的命令处理器
|
||||
const mockCommands = new Map<string, (...args: any[]) => any>();
|
||||
|
||||
// 默认 mock 数据
|
||||
const defaultMocks: Record<string, any> = {
|
||||
// 配置相关
|
||||
get_config: () => ({
|
||||
server: {
|
||||
host: "127.0.0.1",
|
||||
port: 8787,
|
||||
api_key: "",
|
||||
tls: {
|
||||
enable: false,
|
||||
cert_path: null,
|
||||
key_path: null,
|
||||
},
|
||||
},
|
||||
providers: {
|
||||
kiro: {
|
||||
enabled: false,
|
||||
credentials_path: null,
|
||||
region: null,
|
||||
},
|
||||
gemini: {
|
||||
enabled: false,
|
||||
credentials_path: null,
|
||||
},
|
||||
qwen: {
|
||||
enabled: false,
|
||||
credentials_path: null,
|
||||
},
|
||||
openai: {
|
||||
enabled: false,
|
||||
api_key: null,
|
||||
base_url: null,
|
||||
},
|
||||
claude: {
|
||||
enabled: false,
|
||||
api_key: null,
|
||||
base_url: null,
|
||||
},
|
||||
},
|
||||
default_provider: "kiro",
|
||||
remote_management: {
|
||||
allow_remote: false,
|
||||
secret_key: null,
|
||||
disable_control_panel: false,
|
||||
},
|
||||
quota_exceeded: {
|
||||
switch_project: true,
|
||||
switch_preview_model: false,
|
||||
cooldown_seconds: 60,
|
||||
},
|
||||
ampcode: {
|
||||
upstream_url: null,
|
||||
model_mappings: [],
|
||||
restrict_management_to_localhost: true,
|
||||
},
|
||||
credential_pool: {
|
||||
kiro: [],
|
||||
gemini: [],
|
||||
qwen: [],
|
||||
openai: [],
|
||||
claude: [],
|
||||
gemini_api_keys: [],
|
||||
vertex_api_keys: [],
|
||||
codex: [],
|
||||
iflow: [],
|
||||
},
|
||||
proxy_url: null,
|
||||
minimize_to_tray: false,
|
||||
language: "zh",
|
||||
experimental: {
|
||||
screenshot_chat: {
|
||||
enabled: false,
|
||||
shortcut: "",
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
save_config: (config: any) => {
|
||||
console.log("[Mock] Config saved:", config);
|
||||
return { success: true };
|
||||
},
|
||||
|
||||
// Provider 相关
|
||||
get_providers: () => [],
|
||||
get_credentials: () => [],
|
||||
get_default_provider: () => "kiro",
|
||||
set_default_provider: (args: any) => {
|
||||
const provider = args?.provider ?? args;
|
||||
console.log("[Mock] Default provider set to:", provider);
|
||||
return provider;
|
||||
},
|
||||
get_available_models: () => [],
|
||||
|
||||
// 服务器相关
|
||||
get_server_status: () => ({
|
||||
running: false,
|
||||
host: "127.0.0.1",
|
||||
port: 8787,
|
||||
requests: 0,
|
||||
uptime_secs: 0,
|
||||
}),
|
||||
check_server_status: () => ({
|
||||
running: false,
|
||||
host: "127.0.0.1",
|
||||
port: 8787,
|
||||
requests: 0,
|
||||
uptime_secs: 0,
|
||||
}),
|
||||
start_server: () => "Server started (mock)",
|
||||
stop_server: () => "Server stopped (mock)",
|
||||
|
||||
// 网络相关
|
||||
get_network_info: () => ({
|
||||
localhost: "127.0.0.1",
|
||||
lan_ip: "192.168.1.100",
|
||||
all_ips: ["127.0.0.1", "192.168.1.100"],
|
||||
}),
|
||||
|
||||
// Agent 相关
|
||||
list_agent_sessions: () => [],
|
||||
agent_list_sessions: () => [],
|
||||
get_agent_process_status: () => ({ running: false }),
|
||||
agent_get_process_status: () => ({ running: false }),
|
||||
agent_start_process: () => ({ success: true }),
|
||||
agent_stop_process: () => ({ success: true }),
|
||||
agent_create_session: () => ({ session_id: "mock-session-id" }),
|
||||
agent_send_message: () => ({ message_id: "mock-message-id" }),
|
||||
agent_get_session: () => ({ session: null }),
|
||||
agent_delete_session: () => ({ success: true }),
|
||||
agent_get_session_messages: () => [],
|
||||
agent_chat_stream: () => ({}),
|
||||
agent_terminal_command_response: () => ({}),
|
||||
agent_term_scrollback_response: () => ({}),
|
||||
native_agent_chat_stream: () => ({}),
|
||||
|
||||
// Goose Agent
|
||||
goose_agent_init: () => ({ success: true }),
|
||||
goose_agent_status: () => ({ initialized: false }),
|
||||
goose_agent_reset: () => ({ success: true }),
|
||||
goose_agent_create_session: () => ({ session_id: "mock-goose-session" }),
|
||||
goose_agent_send_message: () => ({ message_id: "mock-message-id" }),
|
||||
goose_agent_extend_system_prompt: () => ({ success: true }),
|
||||
goose_agent_list_providers: () => [],
|
||||
|
||||
// 终端相关
|
||||
create_terminal_session: () => ({ uuid: "mock-terminal-uuid" }),
|
||||
terminal_create_session: () => ({ uuid: "mock-terminal-uuid" }),
|
||||
terminal_write: () => ({}),
|
||||
terminal_resize: () => ({}),
|
||||
terminal_close: () => ({}),
|
||||
read_terminal_output: () => [],
|
||||
list_terminal_sessions: () => [],
|
||||
|
||||
// 技能相关
|
||||
get_all_skills: () => [],
|
||||
get_skills_for_app: () => [],
|
||||
get_skill_repos: () => [],
|
||||
add_skill_repo: () => ({ success: true }),
|
||||
remove_skill_repo: () => ({ success: true }),
|
||||
get_installed_proxycast_skills: () => [],
|
||||
install_skill_for_app: () => ({ success: true }),
|
||||
uninstall_skill_for_app: () => ({ success: true }),
|
||||
enable_skill: () => ({ success: true }),
|
||||
disable_skill: () => ({ success: true }),
|
||||
|
||||
// 插件相关
|
||||
get_plugins_with_ui: () => [],
|
||||
get_plugin_status: () => ({
|
||||
enabled: true,
|
||||
plugin_count: 0,
|
||||
plugins_dir: "/mock/plugins",
|
||||
}),
|
||||
get_plugins: () => [],
|
||||
list_installed_plugins: () => [],
|
||||
enable_plugin: () => ({ success: true }),
|
||||
disable_plugin: () => ({ success: true }),
|
||||
reload_plugins: () => ({ success: true }),
|
||||
unload_plugin: () => ({ success: true }),
|
||||
uninstall_plugin: () => ({ success: true }),
|
||||
launch_plugin_ui: () => ({}),
|
||||
|
||||
// 凭证池相关
|
||||
get_relay_providers: () => [],
|
||||
list_relay_providers: () => [],
|
||||
get_pool_overview: () => [],
|
||||
get_provider_pool_overview: () => [],
|
||||
get_provider_pool_credentials: () => [],
|
||||
add_provider_pool_credential: () => ({ success: true }),
|
||||
update_provider_pool_credential: () => ({ success: true }),
|
||||
delete_provider_pool_credential: () => ({ success: true }),
|
||||
toggle_provider_pool_credential: () => ({ success: true }),
|
||||
reset_provider_pool_credential: () => ({ success: true }),
|
||||
reset_provider_pool_health: () => ({ success: true }),
|
||||
check_provider_pool_credential_health: () => ({ healthy: false }),
|
||||
check_provider_pool_type_health: () => ({ healthy: false }),
|
||||
|
||||
// API Key Provider 相关
|
||||
get_api_key_providers: () => [],
|
||||
get_api_key_provider: () => null,
|
||||
add_custom_api_key_provider: () => ({ success: true }),
|
||||
update_api_key_provider: () => ({ success: true }),
|
||||
delete_custom_api_key_provider: () => ({ success: true }),
|
||||
add_api_key: () => ({ success: true }),
|
||||
delete_api_key: () => ({ success: true }),
|
||||
toggle_api_key: () => ({ success: true }),
|
||||
update_api_key_alias: () => ({ success: true }),
|
||||
get_next_api_key: () => null,
|
||||
record_api_key_usage: () => ({}),
|
||||
record_api_key_error: () => ({}),
|
||||
get_provider_ui_state: () => null,
|
||||
set_provider_ui_state: () => ({}),
|
||||
update_provider_sort_orders: () => ({ success: true }),
|
||||
export_api_key_providers: () => ({ config: "{}" }),
|
||||
import_api_key_providers: () => ({ success: true }),
|
||||
get_legacy_api_key_credentials: () => [],
|
||||
migrate_legacy_api_key_credentials: () => ({ success: true }),
|
||||
delete_legacy_api_key_credential: () => ({ success: true }),
|
||||
get_local_kiro_credential_uuid: () => null,
|
||||
|
||||
// OAuth 凭证相关
|
||||
add_kiro_oauth_credential: () => ({ success: true }),
|
||||
add_kiro_from_json: () => ({ success: true }),
|
||||
add_gemini_oauth_credential: () => ({ success: true }),
|
||||
add_qwen_oauth_credential: () => ({ success: true }),
|
||||
add_openai_key_credential: () => ({ success: true }),
|
||||
add_claude_key_credential: () => ({ success: true }),
|
||||
add_gemini_api_key_credential: () => ({ success: true }),
|
||||
add_antigravity_oauth_credential: () => ({ success: true }),
|
||||
add_codex_oauth_credential: () => ({ success: true }),
|
||||
add_claude_oauth_credential: () => ({ success: true }),
|
||||
add_iflow_oauth_credential: () => ({ success: true }),
|
||||
add_iflow_cookie_credential: () => ({ success: true }),
|
||||
start_kiro_builder_id_login: () => ({ success: true }),
|
||||
poll_kiro_builder_id_auth: () => ({ status: "pending" }),
|
||||
cancel_kiro_builder_id_login: () => ({ success: true }),
|
||||
add_kiro_from_builder_id_auth: () => ({ success: true }),
|
||||
start_kiro_social_auth_login: () => ({ success: true }),
|
||||
exchange_kiro_social_auth_token: () => ({ success: true }),
|
||||
cancel_kiro_social_auth_login: () => ({ success: true }),
|
||||
start_kiro_social_auth_callback_server: () => ({ success: true }),
|
||||
refresh_pool_credential_token: () => ({ success: true }),
|
||||
get_pool_credential_oauth_status: () => ({ status: "unknown" }),
|
||||
migrate_private_config_to_pool: () => ({ success: true }),
|
||||
get_credential_health: () => ({ healthy: false }),
|
||||
get_all_credential_health: () => [],
|
||||
get_kiro_credential_fingerprint: () => ({ fingerprint: "" }),
|
||||
switch_kiro_to_local: () => ({ success: true }),
|
||||
|
||||
// Playwright 相关
|
||||
check_playwright_available: () => ({ available: false }),
|
||||
install_playwright: () => ({ success: true }),
|
||||
start_kiro_playwright_login: () => ({ success: true }),
|
||||
cancel_kiro_playwright_login: () => ({ success: true }),
|
||||
|
||||
// OAuth 插件相关
|
||||
init_oauth_plugin_system: () => ({}),
|
||||
enable_oauth_plugin: () => ({ success: true }),
|
||||
disable_oauth_plugin: () => ({ success: true }),
|
||||
uninstall_oauth_plugin: () => ({ success: true }),
|
||||
update_oauth_plugin: () => ({ success: true }),
|
||||
update_oauth_plugin_config: () => ({ success: true }),
|
||||
reload_oauth_plugins: () => ({ success: true }),
|
||||
|
||||
// 连接相关
|
||||
list_connections: () => [],
|
||||
connection_list: () => [],
|
||||
get_oauth_url: () => ({ url: "https://example.com/oauth" }),
|
||||
save_oauth_credential: () => ({ success: true }),
|
||||
get_oauth_credentials: () => [],
|
||||
get_all_oauth_credentials: () => [],
|
||||
reload_oauth_credentials: () => ({ success: true }),
|
||||
refresh_oauth_token: () => ({ success: true }),
|
||||
get_oauth_env_variables: () => [],
|
||||
get_oauth_token_file_hash: () => ({ hash: "" }),
|
||||
check_and_reload_oauth_credentials: () => ({
|
||||
changed: false,
|
||||
new_hash: "",
|
||||
reloaded: false,
|
||||
}),
|
||||
|
||||
// 模型相关
|
||||
get_model_registry: () => [],
|
||||
refresh_model_registry: () => ({ success: true }),
|
||||
search_models: () => [],
|
||||
get_all_provider_models: () => ({}),
|
||||
get_model_preferences: () => [],
|
||||
toggle_model_favorite: () => ({ success: true }),
|
||||
hide_model: () => ({ success: true }),
|
||||
record_model_usage: () => ({}),
|
||||
get_model_sync_state: () => ({ syncing: false, last_sync_at: null }),
|
||||
get_models_for_provider: () => [],
|
||||
get_models_by_tier: () => [],
|
||||
get_provider_alias_config: () => ({ alias: {} }),
|
||||
get_all_alias_configs: () => ({}),
|
||||
|
||||
// Orchestrator 相关
|
||||
init_orchestrator: () => ({}),
|
||||
get_orchestrator_config: () => ({ config: {} }),
|
||||
update_orchestrator_config: () => ({ success: true }),
|
||||
get_pool_stats: () => ({ stats: {} }),
|
||||
get_tier_models: () => [],
|
||||
get_all_models: () => [],
|
||||
update_orchestrator_credentials: () => ({ success: true }),
|
||||
add_orchestrator_credential: () => ({ success: true }),
|
||||
remove_orchestrator_credential: () => ({ success: true }),
|
||||
mark_credential_unhealthy: () => ({ success: true }),
|
||||
mark_credential_healthy: () => ({ success: true }),
|
||||
update_credential_load: () => ({ success: true }),
|
||||
select_model: () => ({ model: "" }),
|
||||
quick_select_model: () => ({ model: "" }),
|
||||
select_model_for_task: () => ({ model: "" }),
|
||||
list_strategies: () => [],
|
||||
list_service_tiers: () => [],
|
||||
list_task_hints: () => [],
|
||||
|
||||
// MCP 相关
|
||||
get_mcp_servers: () => [],
|
||||
add_mcp_server: () => ({ success: true }),
|
||||
update_mcp_server: () => ({ success: true }),
|
||||
delete_mcp_server: () => ({ success: true }),
|
||||
toggle_mcp_server: () => ({ success: true }),
|
||||
import_mcp_from_app: () => ({ success: true }),
|
||||
sync_all_mcp_to_live: () => ({ success: true }),
|
||||
sync_from_external_config: () => ({ success: true }),
|
||||
|
||||
// Switch Provider 相关
|
||||
get_switch_providers: () => [],
|
||||
add_switch_provider: () => ({ success: true }),
|
||||
delete_switch_provider: () => ({ success: true }),
|
||||
update_switch_provider: () => ({ success: true }),
|
||||
get_current_switch_provider: () => null,
|
||||
read_live_provider_settings: () => ({}),
|
||||
|
||||
// Flow Monitor 相关
|
||||
subscribe_flow_events: () => ({ success: true }),
|
||||
query_flows: () => ({ flows: [], total: 0 }),
|
||||
query_flows_with_expression: () => ({ flows: [], total: 0 }),
|
||||
get_flow_detail: () => ({ flow: null }),
|
||||
search_flows: () => ({ flows: [] }),
|
||||
get_flow_stats: () => ({ stats: {} }),
|
||||
update_flow_annotations: () => ({ success: true }),
|
||||
cleanup_flows: () => ({ deleted_count: 0 }),
|
||||
get_recent_flows: () => [],
|
||||
toggle_flow_starred: () => ({ success: true }),
|
||||
get_all_flow_tags: () => [],
|
||||
delete_flow: () => ({ success: true }),
|
||||
delete_flows: () => ({ success: true }),
|
||||
get_flow_monitor_debug_info: () => ({ info: {} }),
|
||||
create_test_flows: () => ({ created_count: 0 }),
|
||||
get_enhanced_stats: () => ({ stats: {} }),
|
||||
get_request_trend: () => ({ trend: [] }),
|
||||
get_token_distribution: () => ({ distribution: {} }),
|
||||
get_latency_histogram: () => ({ histogram: [] }),
|
||||
export_stats_report: () => ({ report: "" }),
|
||||
get_threshold_config: () => ({ config: {} }),
|
||||
update_threshold_config: () => ({ success: true }),
|
||||
get_request_rate: () => ({ rate: 0 }),
|
||||
set_rate_window: () => ({ success: true }),
|
||||
|
||||
// 系统信息相关
|
||||
subscribe_sysinfo: () => ({ success: true }),
|
||||
unsubscribe_sysinfo: () => ({ success: true }),
|
||||
|
||||
// Session 相关
|
||||
update_session: () => ({ success: true }),
|
||||
add_flow_to_session: () => ({ success: true }),
|
||||
remove_flow_from_session: () => ({ success: true }),
|
||||
unarchive_session: () => ({ success: true }),
|
||||
archive_session: () => ({ success: true }),
|
||||
delete_session: () => ({ success: true }),
|
||||
|
||||
// Bookmark 相关
|
||||
remove_bookmark: () => ({ success: true }),
|
||||
|
||||
// Intercept 相关
|
||||
intercept_config_set: () => ({ success: true }),
|
||||
intercept_continue: () => ({ success: true }),
|
||||
intercept_cancel: () => ({ success: true }),
|
||||
|
||||
// Quick Filter 相关
|
||||
delete_quick_filter: () => ({ success: true }),
|
||||
|
||||
// Telemetry 相关
|
||||
get_request_logs: () => ({ logs: [] }),
|
||||
get_request_log_detail: () => ({ log: null }),
|
||||
clear_request_logs: () => ({ success: true }),
|
||||
get_stats_summary: () => ({ summary: {} }),
|
||||
get_stats_by_provider: () => ({ stats: [] }),
|
||||
get_stats_by_model: () => ({ stats: [] }),
|
||||
get_token_summary: () => ({ summary: {} }),
|
||||
get_token_stats_by_provider: () => ({ stats: [] }),
|
||||
get_token_stats_by_model: () => ({ stats: [] }),
|
||||
get_token_stats_by_day: () => ({ stats: [] }),
|
||||
|
||||
// Routes 相关
|
||||
get_available_routes: () => ({ routes: [] }),
|
||||
get_route_curl_examples: () => ({ examples: [] }),
|
||||
|
||||
// Prompts 相关
|
||||
get_prompts: () => [],
|
||||
upsert_prompt: () => ({ success: true }),
|
||||
add_prompt: () => ({ success: true }),
|
||||
update_prompt: () => ({ success: true }),
|
||||
delete_prompt: () => ({ success: true }),
|
||||
enable_prompt: () => ({ success: true }),
|
||||
import_prompt_from_file: () => ({ success: true }),
|
||||
get_current_prompt_file_content: () => ({ content: "" }),
|
||||
auto_import_prompt: () => ({ success: true }),
|
||||
switch_prompt: () => ({ success: true }),
|
||||
|
||||
// Browser Interceptor 相关
|
||||
get_browser_interceptor_state: () => ({ running: false }),
|
||||
start_browser_interceptor: () => ({ success: true }),
|
||||
stop_browser_interceptor: () => ({ success: true }),
|
||||
restore_normal_browser_behavior: () => ({ success: true }),
|
||||
temporary_disable_interceptor: () => ({ success: true }),
|
||||
get_intercepted_urls: () => ({ urls: [] }),
|
||||
get_interceptor_history: () => ({ history: [] }),
|
||||
copy_intercepted_url_to_clipboard: () => ({ success: true }),
|
||||
open_url_in_fingerprint_browser: () => ({ success: true }),
|
||||
dismiss_intercepted_url: () => ({ success: true }),
|
||||
update_browser_interceptor_config: () => ({ success: true }),
|
||||
get_default_browser_interceptor_config: () => ({ config: {} }),
|
||||
validate_browser_interceptor_config: () => ({ valid: true }),
|
||||
is_browser_interceptor_running: () => ({ running: false }),
|
||||
get_browser_interceptor_statistics: () => ({ stats: {} }),
|
||||
|
||||
// Notification 相关
|
||||
show_notification: () => ({}),
|
||||
show_url_intercept_notification: () => ({}),
|
||||
show_status_notification: () => ({}),
|
||||
|
||||
// Window 相关
|
||||
get_window_size: () => ({ width: 1280, height: 800 }),
|
||||
set_window_size: () => ({}),
|
||||
get_window_size_options: () => ({ options: [] }),
|
||||
set_window_size_by_option: () => ({}),
|
||||
toggle_fullscreen: () => ({}),
|
||||
is_fullscreen: () => ({ fullscreen: false }),
|
||||
resize_for_flow_monitor: () => ({}),
|
||||
restore_window_size: () => ({}),
|
||||
toggle_window_size: () => ({}),
|
||||
center_window: () => ({}),
|
||||
|
||||
// Usage 相关
|
||||
get_kiro_usage: () => ({ usage: {} }),
|
||||
|
||||
// Resilience 相关
|
||||
get_retry_config: () => ({ config: {} }),
|
||||
update_retry_config: () => ({ success: true }),
|
||||
get_failover_config: () => ({ config: {} }),
|
||||
update_failover_config: () => ({ success: true }),
|
||||
get_switch_log: () => ({ logs: [] }),
|
||||
clear_switch_log: () => ({ success: true }),
|
||||
|
||||
// Machine ID 相关
|
||||
get_current_machine_id: () => ({ machine_id: "" }),
|
||||
set_machine_id: () => ({ success: true }),
|
||||
generate_random_machine_id: () => ({ machine_id: "" }),
|
||||
validate_machine_id: () => ({ valid: true }),
|
||||
check_admin_privileges: () => ({ is_admin: false }),
|
||||
get_os_type: () => ({ os_type: "linux" }),
|
||||
backup_machine_id_to_file: () => ({ success: true }),
|
||||
restore_machine_id_from_file: () => ({ success: true }),
|
||||
format_machine_id: () => ({ formatted: "" }),
|
||||
detect_machine_id_format: () => ({ format: "unknown" }),
|
||||
convert_machine_id_format: () => ({ converted: "" }),
|
||||
get_machine_id_history: () => ({ history: [] }),
|
||||
clear_machine_id_override: () => ({ success: true }),
|
||||
copy_machine_id_to_clipboard: () => ({ success: true }),
|
||||
paste_machine_id_from_clipboard: () => ({ machine_id: "" }),
|
||||
get_system_info: () => ({ info: {} }),
|
||||
|
||||
// Injection 相关
|
||||
get_injection_config: () => ({ config: {} }),
|
||||
set_injection_enabled: () => ({ success: true }),
|
||||
add_injection_rule: () => ({ success: true }),
|
||||
remove_injection_rule: () => ({ success: true }),
|
||||
update_injection_rule: () => ({ success: true }),
|
||||
get_injection_rules: () => ({ rules: [] }),
|
||||
|
||||
// Plugin SDK 相关
|
||||
plugin_notification: () => ({}),
|
||||
plugin_event_emit: () => ({}),
|
||||
plugin_storage_set: () => ({ success: true }),
|
||||
plugin_storage_delete: () => ({ success: true }),
|
||||
plugin_credential_update: () => ({ success: true }),
|
||||
plugin_credential_delete: () => ({ success: true }),
|
||||
plugin_credential_refresh: () => ({ success: true }),
|
||||
plugin_config_set: () => ({ success: true }),
|
||||
plugin_rpc_connect: () => ({ success: true }),
|
||||
plugin_rpc_disconnect: () => ({ success: true }),
|
||||
|
||||
// OAuth 登录相关
|
||||
start_antigravity_oauth_login: () => ({ success: true }),
|
||||
get_antigravity_auth_url_and_wait: () => ({ url: "" }),
|
||||
start_codex_oauth_login: () => ({ success: true }),
|
||||
get_codex_auth_url_and_wait: () => ({ url: "" }),
|
||||
start_claude_oauth_login: () => ({ success: true }),
|
||||
get_claude_oauth_auth_url_and_wait: () => ({ url: "" }),
|
||||
claude_oauth_with_cookie: () => ({ success: true }),
|
||||
start_qwen_device_code_login: () => ({ success: true }),
|
||||
get_qwen_device_code_and_wait: () => ({ code: "" }),
|
||||
start_iflow_oauth_login: () => ({ success: true }),
|
||||
get_iflow_auth_url_and_wait: () => ({ url: "" }),
|
||||
start_gemini_oauth_login: () => ({ success: true }),
|
||||
get_gemini_auth_url_and_wait: () => ({ url: "" }),
|
||||
exchange_gemini_code: () => ({ success: true }),
|
||||
|
||||
// File System 相关
|
||||
reveal_in_finder: () => ({}),
|
||||
open_with_default_app: () => ({}),
|
||||
delete_file: () => ({ success: true }),
|
||||
create_file: () => ({ success: true }),
|
||||
create_directory: () => ({ success: true }),
|
||||
rename_file: () => ({ success: true }),
|
||||
list_dir: (args: any) => ({
|
||||
path: args?.path ?? "~",
|
||||
parentPath: null,
|
||||
entries: [],
|
||||
error: null,
|
||||
}),
|
||||
|
||||
// Log 相关
|
||||
get_logs: () => [],
|
||||
clear_logs: () => ({}),
|
||||
|
||||
// Test 相关
|
||||
test_api: () => ({ success: true, status: 200, body: "", time_ms: 0 }),
|
||||
|
||||
// Kiro Credentials 相关
|
||||
get_kiro_credentials: () => ({ loaded: false }),
|
||||
refresh_kiro_token: () => ({ success: true }),
|
||||
reload_credentials: () => ({ success: true }),
|
||||
get_env_variables: () => [],
|
||||
get_token_file_hash: () => ({ hash: "" }),
|
||||
check_and_reload_credentials: () => ({
|
||||
changed: false,
|
||||
new_hash: "",
|
||||
reloaded: false,
|
||||
}),
|
||||
|
||||
// Gemini Credentials 相关
|
||||
get_gemini_credentials: () => ({ loaded: false }),
|
||||
reload_gemini_credentials: () => ({ success: true }),
|
||||
refresh_gemini_token: () => ({ success: true }),
|
||||
get_gemini_env_variables: () => [],
|
||||
get_gemini_token_file_hash: () => ({ hash: "" }),
|
||||
check_and_reload_gemini_credentials: () => ({
|
||||
changed: false,
|
||||
new_hash: "",
|
||||
reloaded: false,
|
||||
}),
|
||||
|
||||
// Qwen Credentials 相关
|
||||
get_qwen_credentials: () => ({ loaded: false }),
|
||||
reload_qwen_credentials: () => ({ success: true }),
|
||||
refresh_qwen_token: () => ({ success: true }),
|
||||
get_qwen_env_variables: () => [],
|
||||
get_qwen_token_file_hash: () => ({ hash: "" }),
|
||||
check_and_reload_qwen_credentials: () => ({
|
||||
changed: false,
|
||||
new_hash: "",
|
||||
reloaded: false,
|
||||
}),
|
||||
|
||||
// OpenAI Custom 相关
|
||||
get_openai_custom_status: () => ({
|
||||
enabled: false,
|
||||
has_api_key: false,
|
||||
base_url: "",
|
||||
}),
|
||||
set_openai_custom_config: () => ({ success: true }),
|
||||
|
||||
// Claude Custom 相关
|
||||
get_claude_custom_status: () => ({
|
||||
enabled: false,
|
||||
has_api_key: false,
|
||||
base_url: "",
|
||||
}),
|
||||
set_claude_custom_config: () => ({ success: true }),
|
||||
|
||||
// API Compatibility Check 相关
|
||||
check_api_compatibility: () => ({
|
||||
provider: "",
|
||||
overall_status: "ok",
|
||||
checked_at: "",
|
||||
results: [],
|
||||
warnings: [],
|
||||
}),
|
||||
|
||||
// Endpoint Providers 相关
|
||||
get_endpoint_providers: () => ({}),
|
||||
set_endpoint_provider: () => ({ provider: "" }),
|
||||
|
||||
// Experimental Features 相关
|
||||
get_experimental_config: () => ({
|
||||
screenshot_chat: { enabled: false, shortcut: "" },
|
||||
}),
|
||||
save_experimental_config: () => ({}),
|
||||
validate_shortcut: () => ({ valid: true }),
|
||||
update_screenshot_shortcut: () => ({ success: true }),
|
||||
|
||||
// Screenshot Chat 相关
|
||||
send_screenshot_chat: () => ({ success: true }),
|
||||
close_screenshot_chat_window: () => ({}),
|
||||
|
||||
// Update 相关
|
||||
download_update: () => ({ success: true }),
|
||||
skip_update_version: () => ({}),
|
||||
close_update_window: () => ({}),
|
||||
set_update_check_settings: () => ({ success: true }),
|
||||
test_update_window: () => ({}),
|
||||
|
||||
// Auto Fix 相关
|
||||
auto_fix_configuration: () => ({ success: true }),
|
||||
|
||||
// Check Config Sync 相关
|
||||
check_config_sync_status: () => ({ status: "synced" }),
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock invoke function
|
||||
*/
|
||||
export async function invoke<T = any>(
|
||||
cmd: string,
|
||||
args?: Record<string, unknown>,
|
||||
): Promise<T> {
|
||||
console.log(`[Mock] invoke: ${cmd}`, args);
|
||||
|
||||
// 检查是否有自定义 mock
|
||||
if (mockCommands.has(cmd)) {
|
||||
const handler = mockCommands.get(cmd)!;
|
||||
return handler(args);
|
||||
}
|
||||
|
||||
// 使用默认 mock
|
||||
if (cmd in defaultMocks) {
|
||||
return defaultMocks[cmd](args);
|
||||
}
|
||||
|
||||
console.warn(`[Mock] Unhandled command: ${cmd}`);
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a mock command handler
|
||||
*/
|
||||
export function mockCommand(cmd: string, handler: (...args: any[]) => any) {
|
||||
mockCommands.set(cmd, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all mock commands
|
||||
*/
|
||||
export function clearMocks() {
|
||||
mockCommands.clear();
|
||||
}
|
||||
|
||||
// 导出类型以保持兼容
|
||||
export type { InvokeOptions } from "@tauri-apps/api/core";
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/api/event
|
||||
*/
|
||||
|
||||
type EventCallback<T> = (event: T) => void;
|
||||
type UnlistenFn = () => void;
|
||||
|
||||
// 存储事件监听器
|
||||
const listeners = new Map<string, Set<EventCallback<any>>>();
|
||||
|
||||
/**
|
||||
* Mock listen function
|
||||
*/
|
||||
export async function listen<T = any>(
|
||||
event: string,
|
||||
handler: EventCallback<T>,
|
||||
): Promise<UnlistenFn> {
|
||||
console.log(`[Mock] listen: ${event}`);
|
||||
|
||||
if (!listeners.has(event)) {
|
||||
listeners.set(event, new Set());
|
||||
}
|
||||
|
||||
listeners.get(event)!.add(handler);
|
||||
|
||||
// 返回 unlisten 函数
|
||||
return () => {
|
||||
const set = listeners.get(event);
|
||||
if (set) {
|
||||
set.delete(handler);
|
||||
if (set.size === 0) {
|
||||
listeners.delete(event);
|
||||
}
|
||||
}
|
||||
console.log(`[Mock] unlisten: ${event}`);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock once function
|
||||
*/
|
||||
export async function once<T = any>(
|
||||
event: string,
|
||||
handler: EventCallback<T>,
|
||||
): Promise<UnlistenFn> {
|
||||
console.log(`[Mock] once: ${event}`);
|
||||
|
||||
const wrappedHandler = (data: T) => {
|
||||
handler(data);
|
||||
// 自动移除监听器
|
||||
const set = listeners.get(event);
|
||||
if (set) {
|
||||
set.delete(wrappedHandler);
|
||||
}
|
||||
};
|
||||
|
||||
return listen(event, wrappedHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock emit function - 用于触发事件
|
||||
*/
|
||||
export async function emit(event: string, payload?: any): Promise<void> {
|
||||
console.log(`[Mock] emit: ${event}`, payload);
|
||||
|
||||
const set = listeners.get(event);
|
||||
if (set) {
|
||||
set.forEach((handler) => {
|
||||
try {
|
||||
handler({ event, payload });
|
||||
} catch (e) {
|
||||
console.error(`[Mock] Error in event handler for ${event}:`, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发一个事件(用于测试)
|
||||
*/
|
||||
export function triggerEvent(event: string, payload?: any) {
|
||||
emit(event, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有事件监听器
|
||||
*/
|
||||
export function clearAllListeners() {
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
// 导出类型
|
||||
export type { UnlistenFn };
|
||||
|
||||
// 重新导出 EventTarget 等类型(如果需要)
|
||||
export type TauriEvent<T> = {
|
||||
event: Event;
|
||||
payload: T;
|
||||
};
|
||||
|
||||
export type EventTarget = any;
|
||||
|
||||
// 导出 TAURI_BACKEND_COMPAT 的空实现
|
||||
export const TAURI_BACKEND_COMPAT = {
|
||||
loadTauriCompat: async () => {},
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Tauri Mock System - 统一入口
|
||||
*
|
||||
* 在浏览器开发模式下拦截所有 @tauri-apps/* 包的导入
|
||||
* 并提供 mock 实现
|
||||
*/
|
||||
|
||||
// 检查是否在 Tauri 环境中
|
||||
export function isTauriAvailable(): boolean {
|
||||
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
||||
}
|
||||
|
||||
// 初始化 mock 系统
|
||||
export function initMockSystem() {
|
||||
if (isTauriAvailable()) {
|
||||
console.log("[Mock] Running in Tauri environment, skipping mock");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[Mock] Initializing Tauri Mock System for web mode");
|
||||
console.log("[Mock] Running in WEB MODE - some features may not work");
|
||||
console.log("[Mock] For full functionality, run: pnpm run tauri:dev");
|
||||
}
|
||||
|
||||
// 自动初始化
|
||||
if (import.meta.env.DEV && !isTauriAvailable()) {
|
||||
initMockSystem();
|
||||
}
|
||||
|
||||
// 导出所有 mock 模块
|
||||
export * from "./core";
|
||||
export * from "./event";
|
||||
export * from "./window";
|
||||
|
||||
// 导出插件模块,使用别名避免命名冲突
|
||||
export { open as openFileDialog, save as saveDialog } from "./plugin-dialog";
|
||||
export { open as openShell } from "./plugin-shell";
|
||||
export * from "./plugin-deep-link";
|
||||
export * from "./plugin-global-shortcut";
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/plugin-deep-link
|
||||
*/
|
||||
|
||||
type UrlCallback = (urls: string[]) => void;
|
||||
type UnlistenFn = () => void;
|
||||
|
||||
/**
|
||||
* Mock onOpenUrl function
|
||||
* 在浏览器环境中,deep link 通常不可用
|
||||
*/
|
||||
export async function onOpenUrl(handler: UrlCallback): Promise<UnlistenFn> {
|
||||
console.log("[Mock] Deep link onOpenUrl registered");
|
||||
|
||||
// 模拟从 URL 获取 deep link 参数
|
||||
if (typeof window !== "undefined") {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const deepLinkUrl = urlParams.get("proxycast");
|
||||
|
||||
if (deepLinkUrl) {
|
||||
console.log("[Mock] Deep link URL from params:", deepLinkUrl);
|
||||
setTimeout(() => handler([deepLinkUrl]), 100);
|
||||
}
|
||||
}
|
||||
|
||||
// 返回 unlisten 函数
|
||||
return () => {
|
||||
console.log("[Mock] Deep link unlisten");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock getUrls function (获取当前打开的 URL)
|
||||
*/
|
||||
export async function getUrls(): Promise<string[]> {
|
||||
console.log("[Mock] Deep link getUrls");
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const deepLinkUrl = urlParams.get("proxycast");
|
||||
return deepLinkUrl ? [deepLinkUrl] : [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/plugin-dialog
|
||||
*/
|
||||
|
||||
export interface OpenDialogOptions {
|
||||
title?: string;
|
||||
defaultPath?: string;
|
||||
filters?: Array<{ name: string; extensions: string[] }>;
|
||||
multiple?: boolean;
|
||||
directory?: boolean;
|
||||
recursive?: boolean;
|
||||
}
|
||||
|
||||
export interface SaveDialogOptions {
|
||||
title?: string;
|
||||
defaultPath?: string;
|
||||
filters?: Array<{ name: string; extensions: string[] }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock open function (file picker)
|
||||
*/
|
||||
export async function open(
|
||||
options?: OpenDialogOptions,
|
||||
): Promise<string | string[] | null> {
|
||||
console.log("[Mock] Dialog open:", options);
|
||||
|
||||
// 在浏览器中返回 null(用户取消)
|
||||
// 可以通过 prompt 来模拟用户输入
|
||||
if (options?.directory) {
|
||||
return "/mock/path/to/directory";
|
||||
}
|
||||
|
||||
if (options?.multiple) {
|
||||
return ["/mock/path/to/file1.txt", "/mock/path/to/file2.txt"];
|
||||
}
|
||||
|
||||
return "/mock/path/to/file.txt";
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock save function
|
||||
*/
|
||||
export async function save(
|
||||
options?: SaveDialogOptions,
|
||||
): Promise<string | null> {
|
||||
console.log("[Mock] Dialog save:", options);
|
||||
return "/mock/path/to/saved/file.txt";
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/plugin-global-shortcut
|
||||
*/
|
||||
|
||||
type ShortcutHandler = () => void;
|
||||
|
||||
// 存储快捷键监听器
|
||||
const shortcuts = new Map<string, ShortcutHandler>();
|
||||
|
||||
/**
|
||||
* Mock register function
|
||||
*/
|
||||
export async function register(
|
||||
shortcut: string,
|
||||
handler: ShortcutHandler,
|
||||
): Promise<void> {
|
||||
console.log(`[Mock] Global shortcut registered: ${shortcut}`);
|
||||
shortcuts.set(shortcut, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock unregister function
|
||||
*/
|
||||
export async function unregister(shortcut: string): Promise<void> {
|
||||
console.log(`[Mock] Global shortcut unregistered: ${shortcut}`);
|
||||
shortcuts.delete(shortcut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock unregisterAll function
|
||||
*/
|
||||
export async function unregisterAll(): Promise<void> {
|
||||
console.log("[Mock] All global shortcuts unregistered");
|
||||
shortcuts.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock isRegistered function
|
||||
*/
|
||||
export async function isRegistered(shortcut: string): Promise<boolean> {
|
||||
return shortcuts.has(shortcut);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发快捷键(用于测试)
|
||||
*/
|
||||
export function triggerShortcut(shortcut: string) {
|
||||
const handler = shortcuts.get(shortcut);
|
||||
if (handler) {
|
||||
console.log(`[Mock] Triggering shortcut: ${shortcut}`);
|
||||
handler();
|
||||
} else {
|
||||
console.warn(`[Mock] Shortcut not found: ${shortcut}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/plugin-shell
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mock open function (opens URL in external browser)
|
||||
*/
|
||||
export async function open(path: string, openWith?: string): Promise<void> {
|
||||
console.log("[Mock] Shell open:", path, openWith ? `with: ${openWith}` : "");
|
||||
|
||||
// 在浏览器开发环境中,直接在当前标签页打开
|
||||
if (typeof window !== "undefined") {
|
||||
if (path.startsWith("http://") || path.startsWith("https://")) {
|
||||
window.open(path, "_blank");
|
||||
} else {
|
||||
console.warn("[Mock] Non-HTTP URL, not opening:", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Mock for @tauri-apps/api/window
|
||||
*/
|
||||
|
||||
import { emit } from "./event";
|
||||
|
||||
export interface WindowOptions {
|
||||
width?: number;
|
||||
height?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
title?: string;
|
||||
visible?: boolean;
|
||||
resizable?: boolean;
|
||||
decorations?: boolean;
|
||||
alwaysOnTop?: boolean;
|
||||
skipTaskbar?: boolean;
|
||||
fullscreen?: boolean;
|
||||
maximized?: boolean;
|
||||
minimizable?: boolean;
|
||||
maximizable?: boolean;
|
||||
closable?: boolean;
|
||||
center?: boolean;
|
||||
}
|
||||
|
||||
class MockWindow {
|
||||
label: string;
|
||||
options: WindowOptions;
|
||||
|
||||
constructor(label: string, options: WindowOptions = {}) {
|
||||
this.label = label;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
async emit(event: string, payload?: any): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} emit: ${event}`, payload);
|
||||
return emit(event, payload);
|
||||
}
|
||||
|
||||
async listen(event: string, handler: any): Promise<() => void> {
|
||||
console.log(`[Mock] Window ${this.label} listen: ${event}`);
|
||||
const { listen } = await import("./event");
|
||||
return listen(event, handler);
|
||||
}
|
||||
|
||||
// 窗口控制方法
|
||||
async show(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} show`);
|
||||
this.options.visible = true;
|
||||
}
|
||||
|
||||
async hide(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} hide`);
|
||||
this.options.visible = false;
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} close`);
|
||||
}
|
||||
|
||||
async minimize(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} minimize`);
|
||||
}
|
||||
|
||||
async maximize(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} maximize`);
|
||||
this.options.maximized = true;
|
||||
}
|
||||
|
||||
async unmaximize(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} unmaximize`);
|
||||
this.options.maximized = false;
|
||||
}
|
||||
|
||||
async center(): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} center`);
|
||||
}
|
||||
|
||||
async setTitle(title: string): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} setTitle: ${title}`);
|
||||
this.options.title = title;
|
||||
}
|
||||
|
||||
async resize(width: number, height: number): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} resize: ${width}x${height}`);
|
||||
this.options.width = width;
|
||||
this.options.height = height;
|
||||
}
|
||||
|
||||
async setPosition(x: number, y: number): Promise<void> {
|
||||
console.log(`[Mock] Window ${this.label} setPosition: ${x},${y}`);
|
||||
this.options.x = x;
|
||||
this.options.y = y;
|
||||
}
|
||||
|
||||
async isVisible(): Promise<boolean> {
|
||||
return this.options.visible ?? true;
|
||||
}
|
||||
|
||||
async isMaximized(): Promise<boolean> {
|
||||
return this.options.maximized ?? false;
|
||||
}
|
||||
|
||||
async isFullscreen(): Promise<boolean> {
|
||||
return this.options.fullscreen ?? false;
|
||||
}
|
||||
|
||||
async isDecorated(): Promise<boolean> {
|
||||
return this.options.decorations ?? true;
|
||||
}
|
||||
|
||||
async isResizable(): Promise<boolean> {
|
||||
return this.options.resizable ?? true;
|
||||
}
|
||||
|
||||
async onFocusChanged(
|
||||
_handler: (focused: boolean) => void,
|
||||
): Promise<() => void> {
|
||||
console.log(`[Mock] Window ${this.label} onFocusChanged`);
|
||||
// 返回 unlisten 函数
|
||||
return () => {};
|
||||
}
|
||||
|
||||
async onScaleChanged(_handler: (scale: number) => void): Promise<() => void> {
|
||||
console.log(`[Mock] Window ${this.label} onScaleChanged`);
|
||||
return () => {};
|
||||
}
|
||||
|
||||
async onThemeChanged(_handler: (theme: string) => void): Promise<() => void> {
|
||||
console.log(`[Mock] Window ${this.label} onThemeChanged`);
|
||||
return () => {};
|
||||
}
|
||||
}
|
||||
|
||||
// 当前窗口实例
|
||||
let currentWindow: MockWindow | null = null;
|
||||
|
||||
export function getCurrentWindow(): MockWindow {
|
||||
if (!currentWindow) {
|
||||
currentWindow = new MockWindow("main", { visible: true });
|
||||
}
|
||||
return currentWindow;
|
||||
}
|
||||
|
||||
export function getAllWindows(): MockWindow[] {
|
||||
return [getCurrentWindow()];
|
||||
}
|
||||
|
||||
export async function getCurrentWindowLabel(): Promise<string> {
|
||||
return getCurrentWindow().label;
|
||||
}
|
||||
|
||||
// 导出常用函数
|
||||
export const appWindow = getCurrentWindow();
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { RootRouter } from "./RootRouter";
|
||||
import "./index.css";
|
||||
|
||||
// Initialize Tauri mock for web mode
|
||||
import "./lib/tauri-mock";
|
||||
import "./lib/tauri-mock/index";
|
||||
|
||||
// Initialize i18n configuration
|
||||
import "./i18n/config";
|
||||
|
||||
@@ -3,6 +3,13 @@ import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import svgr from "vite-plugin-svgr";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// ES 模块中获取 __dirname 的方式
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// 获取 Tauri mock 目录路径
|
||||
const tauriMockDir = path.resolve(__dirname, "./src/lib/tauri-mock");
|
||||
|
||||
export default defineConfig(({ mode }) => ({
|
||||
plugins: [
|
||||
@@ -16,8 +23,30 @@ export default defineConfig(({ mode }) => ({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
// 拦截所有 @tauri-apps/* 导入,重定向到 mock 模块
|
||||
// 这样在浏览器开发模式下可以使用 mock 实现
|
||||
"@tauri-apps/api/core": path.resolve(tauriMockDir, "core.ts"),
|
||||
"@tauri-apps/api/event": path.resolve(tauriMockDir, "event.ts"),
|
||||
"@tauri-apps/api/window": path.resolve(tauriMockDir, "window.ts"),
|
||||
"@tauri-apps/api/app": path.resolve(tauriMockDir, "window.ts"),
|
||||
"@tauri-apps/api/path": path.resolve(tauriMockDir, "window.ts"),
|
||||
// 拦截 Tauri 插件
|
||||
"@tauri-apps/plugin-dialog": path.resolve(tauriMockDir, "plugin-dialog.ts"),
|
||||
"@tauri-apps/plugin-shell": path.resolve(tauriMockDir, "plugin-shell.ts"),
|
||||
"@tauri-apps/plugin-deep-link": path.resolve(tauriMockDir, "plugin-deep-link.ts"),
|
||||
"@tauri-apps/plugin-global-shortcut": path.resolve(tauriMockDir, "plugin-global-shortcut.ts"),
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
// 排除 Tauri 包的预构建,确保 alias 生效
|
||||
exclude: [
|
||||
"@tauri-apps/api",
|
||||
"@tauri-apps/plugin-dialog",
|
||||
"@tauri-apps/plugin-shell",
|
||||
"@tauri-apps/plugin-deep-link",
|
||||
"@tauri-apps/plugin-global-shortcut",
|
||||
],
|
||||
},
|
||||
clearScreen: false,
|
||||
server: {
|
||||
port: 1420,
|
||||
|
||||
Reference in New Issue
Block a user