Files
bilin/src/main/ipc/handlers/chapter.handler.ts
T
bing b33d2e7b34 feat: ship v0.6.0 with cockpit, knowledge base, and chapter bridge
Deliver P5 writer workflow: writing cockpit, manual knowledge CRUD with review, chapter bridge with optional AI, publish status, and stock buffer reminders.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 23:03:11 +08:00

136 lines
3.8 KiB
TypeScript

import { ipcMain } from 'electron'
import { IPC } from '../../../shared/ipc-channels'
import type { ChapterStatus, PublishStatus } from '../../../shared/types'
import { BookRegistryService } from '../../services/book-registry'
import { ftsSync } from '../../services/fts-sync.service'
import { wrap } from '../result'
export function registerChapterHandlers(registry: BookRegistryService): void {
ipcMain.handle(
IPC.VOLUME_CREATE,
(_event, { bookId, name }: { bookId: string; name: string }) =>
wrap(() => {
const repo = registry.getVolumeRepo(bookId)
const volumes = repo.list()
return repo.create(name, volumes.length)
})
)
ipcMain.handle(
IPC.VOLUME_UPDATE,
(
_event,
{ bookId, volumeId, name, description }: { bookId: string; volumeId: string; name?: string; description?: string }
) => wrap(() => registry.getVolumeRepo(bookId).update(volumeId, { name, description }))
)
ipcMain.handle(
IPC.VOLUME_DELETE,
(_event, { bookId, volumeId }: { bookId: string; volumeId: string }) =>
wrap(() => {
registry.getVolumeRepo(bookId).delete(volumeId)
})
)
ipcMain.handle(
IPC.CHAPTER_CREATE,
(
_event,
{ bookId, volumeId, title }: { bookId: string; volumeId: string; title: string }
) =>
wrap(() => {
const repo = registry.getChapterRepo(bookId)
const sortOrder = repo.nextSortOrder(volumeId)
const chapter = repo.create(volumeId, title, sortOrder)
ftsSync.upsert(registry.getDb(bookId), 'chapter', chapter.id, chapter.title, chapter.content)
return chapter
})
)
ipcMain.handle(
IPC.CHAPTER_GET,
(_event, { bookId, chapterId }: { bookId: string; chapterId: string }) =>
wrap(() => {
const ch = registry.getChapterRepo(bookId).get(chapterId)
if (!ch) throw new Error('Chapter not found')
return ch
})
)
ipcMain.handle(
IPC.CHAPTER_UPDATE,
(
_event,
{
bookId,
chapterId,
title,
content,
status,
cursorOffset
}: {
bookId: string
chapterId: string
title?: string
content?: string
status?: ChapterStatus
cursorOffset?: number
}
) =>
wrap(() => {
const chapter = registry.getChapterRepo(bookId).update(chapterId, {
title,
content,
status,
cursorOffset
})
ftsSync.upsert(
registry.getDb(bookId),
'chapter',
chapter.id,
chapter.title,
chapter.content
)
registry.updateMeta(bookId, { lastChapterId: chapterId })
return chapter
})
)
ipcMain.handle(
IPC.CHAPTER_DELETE,
(_event, { bookId, chapterId }: { bookId: string; chapterId: string }) =>
wrap(() => {
registry.getChapterRepo(bookId).delete(chapterId)
ftsSync.remove(registry.getDb(bookId), 'chapter', chapterId)
})
)
ipcMain.handle(
IPC.CHAPTER_REORDER,
(_event, { bookId, volumeId, orderedIds }: { bookId: string; volumeId: string; orderedIds: string[] }) =>
wrap(() => registry.getChapterRepo(bookId).reorderVolume(volumeId, orderedIds))
)
ipcMain.handle(
IPC.CHAPTER_MOVE_TO_VOLUME,
(
_event,
{
bookId,
chapterId,
targetVolumeId,
targetIndex
}: { bookId: string; chapterId: string; targetVolumeId: string; targetIndex: number }
) =>
wrap(() => registry.getChapterRepo(bookId).moveToVolume(chapterId, targetVolumeId, targetIndex))
)
ipcMain.handle(
IPC.CHAPTER_SET_PUBLISH_STATUS,
(
_event,
{ bookId, chapterId, publishStatus }: { bookId: string; chapterId: string; publishStatus: PublishStatus }
) => wrap(() => registry.getChapterRepo(bookId).setPublishStatus(chapterId, publishStatus))
)
}