feat(contract): export wire contract from backend and generate frontend types

Adds a zero-dependency `frontend-contract` bin that serializes the real
NoticeStatus variants and FrontendEvent payloads, scripts/gen-contract.mjs
which emits the committed src/services/contract.ts, and a CI job that
regenerates it and fails on a non-empty diff. events.ts now derives its
event map from the generated contract instead of hand-typed shapes.
This commit is contained in:
Tunglies
2026-10-01 14:34:17 +08:00
committed by GitHub
parent 96d68b057a
commit 5bf0de0d0b
10 changed files with 390 additions and 121 deletions
+63
View File
@@ -0,0 +1,63 @@
// @generated by scripts/gen-contract.mjs from the backend wire contract. DO NOT EDIT.
// Regen: pnpm gen:contract
import type { RunState } from './cmds'
/** Wire status strings from NoticeStatus; keep in sync via `pnpm gen:contract`. */
export type NoticeStatus =
| 'info'
| 'import_sub_url::ok'
| 'import_sub_url::error'
| 'set_config::error'
| 'core_start::error'
| 'service_core::repair_required'
| 'service_core::app_data_not_owned'
| 'service_core::sidecar_fallback'
| 'dns_override::auto_disabled'
| 'enhance::discarded_keys'
| 'tun_mode::auto_disabled'
| 'tun_mode::auto_disable_failed'
| 'app_restart::core_stop_failed'
| 'app_quit::core_stop_failed'
| 'update_with_clash_proxy'
| 'update_failed_even_with_clash'
| 'reactivate_profiles::error'
| 'update_failed'
| 'config_validate::boot_error'
| 'config_validate::error'
| 'config_validate::process_terminated'
| 'config_validate::script_error'
| 'config_validate::script_syntax_error'
| 'config_validate::script_missing_main'
| 'config_validate::file_not_found'
| 'config_validate::yaml_syntax_error'
| 'config_validate::yaml_read_error'
| 'config_validate::yaml_mapping_error'
| 'config_validate::merge_syntax_error'
| 'config_validate::merge_mapping_error'
| 'config_core::change_success'
| 'config_core::change_error'
| 'mixed_port::fallback'
| 'mixed_port::fallback_error'
| 'config_validate::core_change'
| 'config_validate::stdout_error'
| 'config_validate::yaml_key_error'
| 'config_validate::yaml_error'
| 'config_validate::merge_key_error'
| 'config_validate::merge_error'
| 'set_config::ok'
/** Event name → payload type for every backend-emitted event. */
export interface VergeEventPayloads {
'verge://refresh-clash-config': string
'verge://refresh-verge-config': string
'verge://refresh-profiles': string
'verge://refresh-proxy-config': null
'verge://notice-message': [NoticeStatus, string]
'verge://timer-updated': string
'verge://run-state-changed': RunState
'verge://pending-failures-changed': null
'profile-changed': string
'profile-update-started': { uid: string }
'profile-update-completed': { uid: string }
}
+3 -15
View File
@@ -1,21 +1,9 @@
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
import type { RunState } from './cmds'
import type { VergeEventPayloads } from './contract'
/** Centralizes frontend event names and payload types for the unchecked Rust IPC seam. */
interface VergeEvents {
'verge://refresh-clash-config': string
'verge://refresh-verge-config': string
'verge://refresh-profiles': string
'verge://refresh-proxy-config': null
/** A backend message for the user: `[status, message]`. */
'verge://notice-message': [string, string]
'verge://timer-updated': string
'verge://run-state-changed': RunState
'verge://pending-failures-changed': null
'profile-changed': string
'profile-update-started': { uid?: string }
'profile-update-completed': { uid?: string }
/** Generated wire contract plus the frontend-internal test-all event. */
interface VergeEvents extends VergeEventPayloads {
'verge://test-all': null
}