feat(desktop): add client release updater
Desktop Client Build / Resolve Build Metadata (push) Successful in 19s
Frontend CI / Frontend (push) Successful in 3m20s
Backend CI / Backend (push) Successful in 16m48s
Desktop Client Build / Build Desktop Client (push) Successful in 24m46s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 37s

This commit is contained in:
2026-05-25 19:23:49 +08:00
parent 41b4a765ac
commit 5f6e9f11da
46 changed files with 5508 additions and 160 deletions
@@ -13,6 +13,7 @@ import type {
DesktopArticleContent,
DesktopClientHeartbeatRequest,
DesktopClientHeartbeatResponse,
DesktopClientReleaseCheckResponse,
DesktopClientRotateResponse,
DesktopPublishTaskListResponse,
DesktopRuntimeSessionSyncRequest,
@@ -35,13 +36,13 @@ import type {
} from '@geo/shared-types'
import { app } from 'electron/main'
import { normalizeDesktopApiBaseURL } from '../../shared/api-base-url'
import {
failObservedRequest,
resolveObservedRequest,
startObservedRequest,
} from '../network-observer'
import { canUseRendererDevtoolsProxy, rendererDevtoolsFetch } from '../renderer-devtools-proxy'
import { normalizeDesktopApiBaseURL } from '../../shared/api-base-url'
type TransportAuthState = 'pending' | 'registered' | 'expired'
type TransportDispatchState = 'idle' | 'connecting' | 'streaming'
@@ -225,10 +226,7 @@ function normalizeErrorForDiagnostics(error: unknown): Record<string, unknown> {
}
}
function appendAccountUpsertDiagnostic(
payload: UpsertDesktopAccountRequest,
error: unknown,
): void {
function appendAccountUpsertDiagnostic(payload: UpsertDesktopAccountRequest, error: unknown): void {
const target = join(app.getPath('userData'), ACCOUNT_UPSERT_DIAGNOSTIC_FILE)
const event = {
at: new Date().toISOString(),
@@ -514,6 +512,44 @@ export async function rotateDesktopClient(): Promise<DesktopClientRotateResponse
)
}
export async function checkDesktopClientRelease(params: {
platform: string
arch: string
version: string
channel?: string
}): Promise<DesktopClientReleaseCheckResponse> {
const search = new URLSearchParams({
platform: params.platform,
arch: params.arch,
version: params.version,
})
if (params.channel?.trim()) {
search.set('channel', params.channel.trim())
}
return desktopGet<DesktopClientReleaseCheckResponse>(
`/api/desktop/clients/releases/latest?${search.toString()}`,
)
}
export async function resolveDesktopClientReleaseDownloadURL(params: {
platform: string
arch: string
version: string
channel?: string
}): Promise<{ download_url: string; expires_in?: number | null }> {
const search = new URLSearchParams({
platform: params.platform,
arch: params.arch,
version: params.version,
})
if (params.channel?.trim()) {
search.set('channel', params.channel.trim())
}
return desktopGet<{ download_url: string; expires_in?: number | null }>(
`/api/desktop/clients/releases/download-url?${search.toString()}`,
)
}
export async function offlineDesktopClient(): Promise<void> {
await desktopPost<{ server_time: string }, Record<string, never>>(
'/api/desktop/clients/offline',