d3ro-voice/apps/desktop/src/main/update-feed.ts
Yun Chan 0fbbbc1756
Some checks failed
deploy-site / deploy (push) Failing after 1m15s
fix(release): restore automatic updates by shipping the speech engine on demand
Auto-update could not work at all: the installer was 189 MB because it carried
the local speech engine and ffmpeg, and the download feed rejects uploads over
about 100 MiB, so update metadata could never be published.

The installer now leaves those components out and the app fetches them the first
time they are needed, verifying every part and the joined archive before
installing. The installer is 90.6 MiB, the update feed is published again, and
updates stay small because the engine is not re-sent on every release.

The fetch is visible and recoverable: the download runs with progress, a failed
install cleans up after itself, and Settings > STT shows the runtime status with
a manual download action for when the automatic one cannot run.
2026-09-18 13:51:49 +09:00

53 lines
2.7 KiB
TypeScript

// src/main/update-feed.ts
// 자동 업데이트 feed URL SSOT.
//
// canonical feed는 Forgejo Generic Package Registry의 `d3ro-voice/latest`다.
// `publish-forgejo-release.mjs`가 latest.yml + 설치파일 + update-policy.json을
// 게시하면 electron-updater가 이 URL에서 latest.yml을 읽어 업데이트를 감지한다.
//
// 전제: Forgejo에서 해당 owner/package의 무인증 pull이 허용돼야 한다
// (비활성 시 무인증 다운로드가 401 — 앱은 조용히 업데이트 체크를 건너뜀).
//
// 빈 문자열이면 UpdateService가 비활성 상태로 동작한다.
// 버전 없는 `latest` 패키지를 가리켜야 기존 설치본이 새 릴리스를 계속 찾을 수 있다.
export const UPDATE_FEED_URL =
'https://git.chanpaca.net/api/packages/yunchan/generic/d3ro-voice/latest'
// GitLab Generic Registry legacy mirror. 2026-08 이전 설치본(0.2.1-alpha)은
// 이 feed를 폴링하므로, 새 설치자가 Forgejo feed를 내장할 때까지 publisher가
// 함께 게시한다. 마이그레이션 완료 후 제거 가능. 런타임은 참조하지 않는다.
/**
* 로컬 AI 런타임(사이드카 엔진 / ffmpeg) 배포 위치.
* 진을 설치본에 넣으면 installer가 Cloudflare 업로드 한도(100MiB)를 넘어 업데이트
* 메타데이터(latest.yml)를 게시할 수 없다. 그래서 런타임은 별도 경로에서 필요할 때 받는다.
* 자동 업데이트 채널과 분리된 경로이며 서명이 필요 없다.
*/
export const RUNTIME_FEED_URL = UPDATE_FEED_URL.replace(/\/latest$/, '/runtime-latest')
/** 런타임 인덱스 파일명 (feed 루트) */
export const RUNTIME_INDEX_FILENAME = 'runtime.json'
export const LEGACY_UPDATE_FEED_URL =
'https://gitlab.twentyoz.kr:8443/api/v4/projects/1172/packages/generic/d3ro-voice/latest'
/** 업데이트 채널. `latest`=stable, `beta`, `alpha` 순으로 불안정. */
export type UpdateChannel = 'latest' | 'beta' | 'alpha'
export const UPDATE_CHANNELS: readonly UpdateChannel[] = ['latest', 'beta', 'alpha']
/** 채널별 electron-builder update metadata 파일명. */
export function channelMetadataName(channel: UpdateChannel): string {
return channel === 'latest' ? 'latest.yml' : `${channel}.yml`
}
/** 원격 업데이트 정책 파일명. feed 루트에서 내려받는다. */
export const UPDATE_POLICY_FILENAME = 'update-policy.json'
/** 원격 업데이트 정책 URL (없으면 앱 내장 기본 정책으로 폴백). */
export const UPDATE_POLICY_URL = UPDATE_FEED_URL
? `${UPDATE_FEED_URL}/${UPDATE_POLICY_FILENAME}`
: ''
export function isUpdateChannel(value: unknown): value is UpdateChannel {
return typeof value === 'string' && (UPDATE_CHANNELS as readonly string[]).includes(value)
}