refactor: consolidate IPC types into src/shared/types.ts

The 12 cross-process data types were manually copied across
src/preload/index.ts and src/renderer/src/types/t4sd.d.ts. A silent
field addition or rename in either file would not produce a compile
error in the other — the divergence only surfaces at runtime.

A shared module makes the compiler enforce consistency. Preload imports
from shared/types and re-exports for downstream consumers. The renderer's
t4sd.d.ts re-exports the same types from shared/types, so all existing
screen imports continue to work without modification.

Both tsconfigs are extended to include src/shared so the module is
reachable from both composite projects.
This commit is contained in:
Andre
2026-05-15 08:49:31 +02:00
parent 211174f889
commit 13b28fdc91
6 changed files with 153 additions and 181 deletions
+1 -7
View File
@@ -8,10 +8,4 @@ export type Quality =
| 'audio_only'
| 'worst'
export interface PlaybackEvent {
kind: 'started' | 'stopped' | 'error'
channelLogin?: string
message?: string
durationSeconds?: number
isLive?: boolean
}
export type { PlaybackEvent } from '../../shared/types'
+27 -85
View File
@@ -1,91 +1,33 @@
import { contextBridge, ipcRenderer, type IpcRendererEvent } from 'electron'
import { IPC } from '../main/ipc/channels'
import type {
AuthStatus,
DeviceFlowStartInfo,
AuthEvent,
FollowedChannelInfo,
OwnUserInfo,
PlaybackEvent,
HlsUrlPayload,
GameInfo,
VodInfo,
VodProgress,
VodChapter,
TopStreamsResult
} from '../shared/types'
export type AuthStatus = 'logged-out' | 'logged-in'
export interface DeviceFlowStartInfo {
userCode: string
verificationUri: string
expiresInSec: number
}
export type AuthEvent =
| { kind: 'authorized' }
| { kind: 'denied' }
| { kind: 'expired' }
| { kind: 'cancelled' }
| { kind: 'error'; message: string }
export interface FollowedChannelInfo {
broadcasterId: string
broadcasterLogin: string
broadcasterName: string
profileImageUrl: string
isLive: boolean
streamTitle?: string
gameId?: string
gameName?: string
viewerCount?: number
thumbnailUrl?: string
startedAt?: string
language?: string
}
export interface OwnUserInfo {
id: string
login: string
displayName: string
profileImageUrl: string
}
export interface PlaybackEvent {
kind: 'started' | 'stopped' | 'error'
channelLogin?: string
message?: string
durationSeconds?: number
isLive?: boolean
}
export interface HlsUrlPayload {
url: string
isLive: boolean
startPosition: number
durationSeconds: number
vodId?: string
}
export interface GameInfo {
id: string
name: string
boxArtUrl: string
viewerCount?: number
}
export interface VodInfo {
id: string
title: string
createdAt: string
durationSeconds: number
viewCount: number
thumbnailUrl: string
}
export interface VodProgress {
resumePositionSeconds: number
watchedAt: number
completed: boolean
}
export interface VodChapter {
positionSeconds: number
durationSeconds: number
gameName: string
gameId: string | null
}
export interface TopStreamsResult {
streams: FollowedChannelInfo[]
cursor?: string
export type {
AuthStatus,
DeviceFlowStartInfo,
AuthEvent,
FollowedChannelInfo,
OwnUserInfo,
PlaybackEvent,
HlsUrlPayload,
GameInfo,
VodInfo,
VodProgress,
VodChapter,
TopStreamsResult
}
const api = {
+32 -87
View File
@@ -1,92 +1,37 @@
// Spiegel der Preload-API. Manuell synchron halten zu src/preload/index.ts.
// IPC-Channel-Namen: src/main/ipc/channels.ts (Renderer kann nicht direkt importieren).
// Data types: src/shared/types.ts (canonical source, compiler-enforced).
// T4sdApi: keep manually in sync with src/preload/index.ts.
// Direct import is not possible: tsconfig.web.json and tsconfig.node.json are separate
// composite projects — preload/index.ts is not reachable from the renderer build.
export type AuthStatus = 'logged-out' | 'logged-in'
export type {
AuthStatus,
DeviceFlowStartInfo,
AuthEvent,
FollowedChannelInfo,
OwnUserInfo,
PlaybackEvent,
HlsUrlPayload,
GameInfo,
VodInfo,
VodProgress,
VodChapter,
TopStreamsResult
} from '../../../shared/types'
export interface DeviceFlowStartInfo {
userCode: string
verificationUri: string
expiresInSec: number
}
export type AuthEvent =
| { kind: 'authorized' }
| { kind: 'denied' }
| { kind: 'expired' }
| { kind: 'cancelled' }
| { kind: 'error'; message: string }
export interface FollowedChannelInfo {
broadcasterId: string
broadcasterLogin: string
broadcasterName: string
profileImageUrl: string
isLive: boolean
streamTitle?: string
gameId?: string
gameName?: string
viewerCount?: number
thumbnailUrl?: string
startedAt?: string
language?: string
}
export interface OwnUserInfo {
id: string
login: string
displayName: string
profileImageUrl: string
}
export interface GameInfo {
id: string
name: string
boxArtUrl: string
viewerCount?: number
}
export interface PlaybackEvent {
kind: 'started' | 'stopped' | 'error'
channelLogin?: string
message?: string
durationSeconds?: number
isLive?: boolean
}
export interface HlsUrlPayload {
url: string
isLive: boolean
startPosition: number
durationSeconds: number
vodId?: string
}
export interface VodInfo {
id: string
title: string
createdAt: string
durationSeconds: number
viewCount: number
thumbnailUrl: string
}
export interface VodProgress {
resumePositionSeconds: number
watchedAt: number
completed: boolean
}
export interface VodChapter {
positionSeconds: number
durationSeconds: number
gameName: string
gameId: string | null
}
export interface TopStreamsResult {
streams: FollowedChannelInfo[]
cursor?: string
}
import type {
AuthStatus,
DeviceFlowStartInfo,
AuthEvent,
FollowedChannelInfo,
OwnUserInfo,
PlaybackEvent,
HlsUrlPayload,
GameInfo,
VodInfo,
VodProgress,
VodChapter,
TopStreamsResult
} from '../../../shared/types'
export interface T4sdApi {
appVersion: string
+86
View File
@@ -0,0 +1,86 @@
export type AuthStatus = 'logged-out' | 'logged-in'
export interface DeviceFlowStartInfo {
userCode: string
verificationUri: string
expiresInSec: number
}
export type AuthEvent =
| { kind: 'authorized' }
| { kind: 'denied' }
| { kind: 'expired' }
| { kind: 'cancelled' }
| { kind: 'error'; message: string }
export interface FollowedChannelInfo {
broadcasterId: string
broadcasterLogin: string
broadcasterName: string
profileImageUrl: string
isLive: boolean
streamTitle?: string
gameId?: string
gameName?: string
viewerCount?: number
thumbnailUrl?: string
startedAt?: string
language?: string
}
export interface OwnUserInfo {
id: string
login: string
displayName: string
profileImageUrl: string
}
export interface PlaybackEvent {
kind: 'started' | 'stopped' | 'error'
channelLogin?: string
message?: string
durationSeconds?: number
isLive?: boolean
}
export interface HlsUrlPayload {
url: string
isLive: boolean
startPosition: number
durationSeconds: number
vodId?: string
}
export interface GameInfo {
id: string
name: string
boxArtUrl: string
viewerCount?: number
}
export interface VodInfo {
id: string
title: string
createdAt: string
durationSeconds: number
viewCount: number
thumbnailUrl: string
}
export interface VodProgress {
resumePositionSeconds: number
watchedAt: number
completed: boolean
}
export interface VodChapter {
positionSeconds: number
durationSeconds: number
gameName: string
gameId: string | null
}
export interface TopStreamsResult {
streams: FollowedChannelInfo[]
cursor?: string
}