import type { LicenseSnapshot } from '../license/licenseSnapshot'; import type { AssetId, EffectsEvent, EffectsState, GraphNodeId, MaterialId, MaterialsOverlayEvent, MaterialsOverlayState, MediaAsset, NpcId, NpcRelationId, NpcsOverlayEvent, NpcsOverlayState, Project, ProjectId, Scene, SceneDarknessEvent, SceneDarknessState, SceneId, VideoPlaybackEvent, VideoPlaybackState, } from '../types'; import type { SceneImportResolution, StorylineImportMergeReport, StorylineLabels, StorylineListItem, StorylineSelection, } from '../graph/storylineExportImport'; export const ipcChannels = { app: { quit: 'app.quit', getVersion: 'app.getVersion', }, updater: { check: 'updater.check', downloadAndRestart: 'updater.downloadAndRestart', progress: 'updater.progress', }, project: { list: 'project.list', create: 'project.create', open: 'project.open', close: 'project.close', saveNow: 'project.saveNow', get: 'project.get', updateScene: 'project.updateScene', updateConnections: 'project.updateConnections', setCurrentScene: 'project.setCurrentScene', setCurrentGraphNode: 'project.setCurrentGraphNode', importMedia: 'project.importMedia', importCampaignAudio: 'project.importCampaignAudio', updateCampaignAudios: 'project.updateCampaignAudios', upsertMaterial: 'project.upsertMaterial', setMaterialRotation: 'project.setMaterialRotation', deleteMaterial: 'project.deleteMaterial', setMaterialsOrder: 'project.setMaterialsOrder', pickMaterialImage: 'project.pickMaterialImage', upsertNpc: 'project.upsertNpc', updateNpcFields: 'project.updateNpcFields', updateNpcPosition: 'project.updateNpcPosition', deleteNpc: 'project.deleteNpc', setNpcsOrder: 'project.setNpcsOrder', pickNpcAvatar: 'project.pickNpcAvatar', upsertNpcRelation: 'project.upsertNpcRelation', deleteNpcRelation: 'project.deleteNpcRelation', importScenePreview: 'project.importScenePreview', clearScenePreview: 'project.clearScenePreview', assetFileUrl: 'project.assetFileUrl', updateSceneGraphNodePosition: 'project.updateSceneGraphNodePosition', addSceneGraphNode: 'project.addSceneGraphNode', removeSceneGraphNode: 'project.removeSceneGraphNode', addSceneGraphEdge: 'project.addSceneGraphEdge', removeSceneGraphEdge: 'project.removeSceneGraphEdge', setSceneGraphNodeStart: 'project.setSceneGraphNodeStart', setSceneGraphNodeSideStoryStart: 'project.setSceneGraphNodeSideStoryStart', updateSideStoryLineTitle: 'project.updateSideStoryLineTitle', deleteScene: 'project.deleteScene', setSceneListOrder: 'project.setSceneListOrder', rename: 'project.rename', importZip: 'project.importZip', exportZip: 'project.exportZip', getProjectStorylines: 'project.getProjectStorylines', peekImportZip: 'project.peekImportZip', pickImportZipFile: 'project.pickImportZipFile', peekImportZipPath: 'project.peekImportZipPath', peekImportFromProject: 'project.peekImportFromProject', mergeImportZip: 'project.mergeImportZip', mergeImportFromProject: 'project.mergeImportFromProject', importZipFromPath: 'project.importZipFromPath', deleteProject: 'project.deleteProject', importZipProgress: 'project.importZipProgress', exportZipProgress: 'project.exportZipProgress', scenePreviewImportProgress: 'project.scenePreviewImportProgress', }, windows: { openMultiWindow: 'windows.openMultiWindow', closeMultiWindow: 'windows.closeMultiWindow', togglePresentationFullscreen: 'windows.togglePresentationFullscreen', getMultiWindowState: 'windows.getMultiWindowState', multiWindowStateChanged: 'windows.multiWindowStateChanged', openSceneDescription: 'windows.openSceneDescription', closeSceneDescription: 'windows.closeSceneDescription', getSceneDescriptionContent: 'windows.getSceneDescriptionContent', sceneDescriptionContent: 'windows.sceneDescriptionContent', openMaterials: 'windows.openMaterials', closeMaterials: 'windows.closeMaterials', openNpcsEditor: 'windows.openNpcsEditor', closeNpcsEditor: 'windows.closeNpcsEditor', openNpcs: 'windows.openNpcs', closeNpcs: 'windows.closeNpcs', }, session: { stateChanged: 'session.stateChanged', }, effects: { getState: 'effects.getState', dispatch: 'effects.dispatch', stateChanged: 'effects.stateChanged', }, materialsOverlay: { getState: 'materialsOverlay.getState', dispatch: 'materialsOverlay.dispatch', stateChanged: 'materialsOverlay.stateChanged', }, npcsOverlay: { getState: 'npcsOverlay.getState', dispatch: 'npcsOverlay.dispatch', stateChanged: 'npcsOverlay.stateChanged', }, sceneDarkness: { getState: 'sceneDarkness.getState', dispatch: 'sceneDarkness.dispatch', stateChanged: 'sceneDarkness.stateChanged', }, video: { getState: 'video.getState', dispatch: 'video.dispatch', stateChanged: 'video.stateChanged', }, license: { getStatus: 'license.getStatus', setToken: 'license.setToken', clearToken: 'license.clearToken', acceptEula: 'license.acceptEula', statusChanged: 'license.statusChanged', }, } as const; export type ZipProgressEvent = { kind: 'import' | 'export'; stage: 'copy' | 'unzip' | 'zip' | 'done'; percent: number; // 0..100 detail?: string; }; export type ScenePreviewImportEvent = { sceneId: SceneId; assetId: AssetId; phase: 'queued' | 'optimizing' | 'thumbnail' | 'done' | 'error'; project?: Project; message?: string; }; export type UpdaterCheckResponse = | { outcome: 'not_packaged' } | { outcome: 'no_license' } | { outcome: 'current'; currentVersion: string } | { outcome: 'available'; version: string } | { outcome: 'error'; message: string }; export type UpdaterDownloadResponse = { ok: true } | { ok: false; message: string }; export type UpdaterProgressPhase = | 'checking' | 'available' | 'not-available' | 'downloading' | 'installing' | 'error'; export type UpdaterProgressEvent = { phase: UpdaterProgressPhase; /** 0..100 при phase=downloading */ percent?: number; version?: string; message?: string; }; export type IpcEventMap = { [ipcChannels.session.stateChanged]: { state: SessionState }; [ipcChannels.effects.stateChanged]: { state: EffectsState }; [ipcChannels.materialsOverlay.stateChanged]: { state: MaterialsOverlayState }; [ipcChannels.npcsOverlay.stateChanged]: { state: NpcsOverlayState }; [ipcChannels.sceneDarkness.stateChanged]: { state: SceneDarknessState }; [ipcChannels.video.stateChanged]: { state: VideoPlaybackState }; [ipcChannels.license.statusChanged]: { snapshot: LicenseSnapshot }; [ipcChannels.windows.multiWindowStateChanged]: { open: boolean }; [ipcChannels.windows.sceneDescriptionContent]: { html: string }; [ipcChannels.project.importZipProgress]: ZipProgressEvent; [ipcChannels.project.exportZipProgress]: ZipProgressEvent; [ipcChannels.project.scenePreviewImportProgress]: ScenePreviewImportEvent; [ipcChannels.updater.progress]: UpdaterProgressEvent; }; export type IpcInvokeMap = { [ipcChannels.app.quit]: { req: Record; res: { ok: true }; }; [ipcChannels.app.getVersion]: { req: Record; res: { version: string; buildNumber: string | null; packaged: boolean }; }; [ipcChannels.updater.check]: { req: Record; res: UpdaterCheckResponse; }; [ipcChannels.updater.downloadAndRestart]: { req: { version: string }; res: UpdaterDownloadResponse; }; [ipcChannels.project.list]: { req: Record; res: { projects: { id: ProjectId; name: string; updatedAt: string; fileName: string }[] }; }; [ipcChannels.project.create]: { req: { name: string }; res: { project: Project }; }; [ipcChannels.project.open]: { req: { projectId: ProjectId }; res: { project: Project }; }; [ipcChannels.project.close]: { req: Record; res: { ok: true }; }; [ipcChannels.project.get]: { req: Record; res: { project: Project | null }; }; [ipcChannels.project.saveNow]: { req: Record; res: { ok: true }; }; [ipcChannels.project.updateScene]: { req: { sceneId: SceneId; patch: ScenePatch }; res: { scene: Scene }; }; [ipcChannels.project.updateConnections]: { req: { sceneId: SceneId; connections: SceneId[] }; res: { scene: Scene }; }; [ipcChannels.project.setCurrentScene]: { req: { sceneId: SceneId | null }; res: { currentSceneId: SceneId | null }; }; [ipcChannels.project.setCurrentGraphNode]: { req: { graphNodeId: GraphNodeId | null }; res: { currentGraphNodeId: GraphNodeId | null; currentSceneId: SceneId | null }; }; [ipcChannels.project.importMedia]: { req: { sceneId: SceneId; filePaths?: string[] }; res: { project: Project; imported: MediaAsset[] }; }; [ipcChannels.project.importCampaignAudio]: { req: { filePaths?: string[] }; res: { canceled: boolean; project: Project; imported: MediaAsset[] }; }; [ipcChannels.project.updateCampaignAudios]: { req: { audios: Project['campaignAudios'] }; res: { project: Project }; }; [ipcChannels.project.upsertMaterial]: { req: { materialId?: MaterialId; name: string; filePath?: string }; res: { project: Project }; }; [ipcChannels.project.setMaterialRotation]: { req: { materialId: MaterialId; rotationDeg: 0 | 90 | 180 | 270 }; res: { project: Project }; }; [ipcChannels.project.deleteMaterial]: { req: { materialId: MaterialId }; res: { project: Project }; }; [ipcChannels.project.setMaterialsOrder]: { req: { materialIds: MaterialId[] }; res: { project: Project }; }; [ipcChannels.project.pickMaterialImage]: { req: Record; res: | { canceled: true } | { canceled: false; filePath: string; previewDataUrl: string }; }; [ipcChannels.project.upsertNpc]: { req: { npcId?: NpcId; name: string; description?: string; filePath?: string }; res: { project: Project }; }; [ipcChannels.project.updateNpcFields]: { req: { npcId: NpcId; name?: string; description?: string }; res: { project: Project }; }; [ipcChannels.project.updateNpcPosition]: { req: { npcId: NpcId; x: number; y: number }; res: { project: Project }; }; [ipcChannels.project.deleteNpc]: { req: { npcId: NpcId }; res: { project: Project }; }; [ipcChannels.project.setNpcsOrder]: { req: { npcIds: NpcId[] }; res: { project: Project }; }; [ipcChannels.project.pickNpcAvatar]: { req: Record; res: | { canceled: true } | { canceled: false; filePath: string; previewDataUrl: string }; }; [ipcChannels.project.upsertNpcRelation]: { req: { relationId?: NpcRelationId; sourceNpcId: NpcId; targetNpcId: NpcId; label: string; }; res: { project: Project }; }; [ipcChannels.project.deleteNpcRelation]: { req: { relationId: NpcRelationId }; res: { project: Project }; }; [ipcChannels.project.importScenePreview]: { req: { sceneId: SceneId; filePath?: string }; res: { project: Project; assetId: AssetId | null; background: boolean }; }; [ipcChannels.project.clearScenePreview]: { req: { sceneId: SceneId }; res: { project: Project }; }; [ipcChannels.project.assetFileUrl]: { req: { assetId: AssetId }; res: { url: string | null }; }; [ipcChannels.project.updateSceneGraphNodePosition]: { req: { nodeId: GraphNodeId; x: number; y: number }; res: { project: Project }; }; [ipcChannels.project.addSceneGraphNode]: { req: { sceneId: SceneId; x: number; y: number }; res: { project: Project }; }; [ipcChannels.project.removeSceneGraphNode]: { req: { nodeId: GraphNodeId }; res: { project: Project }; }; [ipcChannels.project.addSceneGraphEdge]: { req: { sourceGraphNodeId: GraphNodeId; targetGraphNodeId: GraphNodeId }; res: { project: Project }; }; [ipcChannels.project.removeSceneGraphEdge]: { req: { edgeId: string }; res: { project: Project }; }; [ipcChannels.project.setSceneGraphNodeStart]: { req: { graphNodeId: GraphNodeId | null }; res: { project: Project }; }; [ipcChannels.project.setSceneGraphNodeSideStoryStart]: { req: { graphNodeId: GraphNodeId }; res: { project: Project }; }; [ipcChannels.project.updateSideStoryLineTitle]: { req: { graphNodeId: GraphNodeId; title: string }; res: { project: Project }; }; [ipcChannels.project.deleteScene]: { req: { sceneId: SceneId }; res: { project: Project }; }; [ipcChannels.project.setSceneListOrder]: { req: { sceneListOrder: SceneId[] }; res: { project: Project }; }; [ipcChannels.project.rename]: { req: { name: string; fileBaseName: string }; res: { project: Project }; }; [ipcChannels.project.importZip]: { req: Record; res: { canceled: true } | { canceled: false; project: Project }; }; [ipcChannels.project.getProjectStorylines]: { req: { projectId: ProjectId; labels: StorylineLabels }; res: { storylines: StorylineListItem[] }; }; [ipcChannels.project.peekImportZip]: { req: { labels: StorylineLabels; targetHasMainStart: boolean }; res: | { canceled: true } | { canceled: false; filePath: string; projectName: string; storylines: StorylineListItem[]; sourceProject: Project; }; }; [ipcChannels.project.pickImportZipFile]: { req: Record; res: { canceled: true } | { canceled: false; filePath: string }; }; [ipcChannels.project.peekImportZipPath]: { req: { filePath: string; labels: StorylineLabels; targetHasMainStart: boolean }; res: { filePath: string; projectName: string; storylines: StorylineListItem[]; sourceProject: Project; }; }; [ipcChannels.project.peekImportFromProject]: { req: { sourceProjectId: ProjectId; labels: StorylineLabels; targetHasMainStart: boolean }; res: { sourceProjectId: ProjectId; projectName: string; storylines: StorylineListItem[]; sourceProject: Project; }; }; [ipcChannels.project.mergeImportZip]: { req: { filePath: string; storylineSelections: StorylineSelection[]; sceneResolutions: SceneImportResolution[]; }; res: { project: Project; report: StorylineImportMergeReport }; }; [ipcChannels.project.mergeImportFromProject]: { req: { sourceProjectId: ProjectId; storylineSelections: StorylineSelection[]; sceneResolutions: SceneImportResolution[]; }; res: { project: Project; report: StorylineImportMergeReport }; }; [ipcChannels.project.importZipFromPath]: { req: { filePath: string }; res: { project: Project }; }; [ipcChannels.project.exportZip]: { req: { projectId: ProjectId; storylineSelections: StorylineSelection[]; labels: StorylineLabels }; res: { canceled: true } | { canceled: false }; }; [ipcChannels.project.deleteProject]: { req: { projectId: ProjectId }; res: { ok: true }; }; [ipcChannels.windows.openMultiWindow]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeMultiWindow]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.togglePresentationFullscreen]: { req: Record; res: { ok: true; isFullScreen: boolean }; }; [ipcChannels.windows.getMultiWindowState]: { req: Record; res: { open: boolean }; }; [ipcChannels.windows.openSceneDescription]: { req: { html: string }; res: { ok: true }; }; [ipcChannels.windows.closeSceneDescription]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.getSceneDescriptionContent]: { req: Record; res: { html: string }; }; [ipcChannels.windows.openMaterials]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeMaterials]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.openNpcsEditor]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeNpcsEditor]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.openNpcs]: { req: Record; res: { ok: true }; }; [ipcChannels.windows.closeNpcs]: { req: Record; res: { ok: true }; }; [ipcChannels.materialsOverlay.getState]: { req: Record; res: { state: MaterialsOverlayState }; }; [ipcChannels.materialsOverlay.dispatch]: { req: { event: MaterialsOverlayEvent }; res: { ok: true }; }; [ipcChannels.npcsOverlay.getState]: { req: Record; res: { state: NpcsOverlayState }; }; [ipcChannels.npcsOverlay.dispatch]: { req: { event: NpcsOverlayEvent }; res: { ok: true }; }; [ipcChannels.effects.getState]: { req: Record; res: { state: EffectsState }; }; [ipcChannels.effects.dispatch]: { req: { event: EffectsEvent }; res: { ok: true }; }; [ipcChannels.sceneDarkness.getState]: { req: Record; res: { state: SceneDarknessState }; }; [ipcChannels.sceneDarkness.dispatch]: { req: { event: SceneDarknessEvent }; res: { ok: true }; }; [ipcChannels.video.getState]: { req: Record; res: { state: VideoPlaybackState }; }; [ipcChannels.video.dispatch]: { req: { event: VideoPlaybackEvent }; res: { ok: true }; }; [ipcChannels.license.getStatus]: { req: Record; res: LicenseSnapshot; }; [ipcChannels.license.setToken]: { req: { token: string }; res: LicenseSnapshot; }; [ipcChannels.license.clearToken]: { req: Record; res: LicenseSnapshot; }; [ipcChannels.license.acceptEula]: { req: { version: number }; res: { ok: true }; }; }; export type SessionState = { project: Project | null; currentSceneId: SceneId | null; }; export type LegacyIpcEventMap = { [ipcChannels.session.stateChanged]: { state: SessionState }; [ipcChannels.effects.stateChanged]: { state: EffectsState }; [ipcChannels.materialsOverlay.stateChanged]: { state: MaterialsOverlayState }; [ipcChannels.npcsOverlay.stateChanged]: { state: NpcsOverlayState }; [ipcChannels.sceneDarkness.stateChanged]: { state: SceneDarknessState }; [ipcChannels.video.stateChanged]: { state: VideoPlaybackState }; [ipcChannels.license.statusChanged]: Record; }; export type ScenePatch = { title?: string; description?: string; previewAssetId?: AssetId | null; previewAssetType?: 'image' | 'video' | null; previewThumbAssetId?: AssetId | null; previewVideoAutostart?: boolean; previewRotationDeg?: 0 | 90 | 180 | 270; darkenScene?: boolean; settings?: Partial; media?: Partial; layout?: Partial; };