Files
clash-verge-rev/src/services/events.ts
T
Tunglies 5bf0de0d0b 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.
2026-10-01 14:34:17 +08:00

64 lines
1.7 KiB
TypeScript

import { listen, type UnlistenFn } from '@tauri-apps/api/event'
import type { VergeEventPayloads } from './contract'
/** Generated wire contract plus the frontend-internal test-all event. */
interface VergeEvents extends VergeEventPayloads {
'verge://test-all': null
}
type VergeEventName = keyof VergeEvents
type VergeEventHandlers = {
[Name in VergeEventName]?: (payload: VergeEvents[Name]) => void
}
/**
* Returns synchronous teardown for asynchronous registrations. `onSubscribed` lets callers
* reread event-only state after all listeners are live, closing the initial race window.
*/
export const subscribeVergeEvents = (
handlers: VergeEventHandlers,
onSubscribed?: () => void,
): (() => void) => {
let disposed = false
const unlisteners: UnlistenFn[] = []
const registrations = Object.entries(handlers).map(([name, handler]) => {
if (!handler) return Promise.resolve()
return listen(name, ({ payload }) => {
;(handler as (payload: unknown) => void)(payload)
})
.then((unlisten) => {
// Resolved after teardown: unsubscribe immediately rather than leak.
if (disposed) {
unlisten()
return
}
unlisteners.push(unlisten)
})
.catch((error) => {
console.error(`[events] failed to subscribe to ${name}:`, error)
})
})
if (onSubscribed) {
void Promise.all(registrations).then(() => {
if (disposed) return
onSubscribed()
})
}
return () => {
disposed = true
for (const unlisten of unlisteners.splice(0)) {
try {
unlisten()
} catch (error) {
console.error('[events] teardown failed:', error)
}
}
}
}