(db: Database, getWin: () => BrowserWindow | null)
| 1633 | } |
| 1634 | |
| 1635 | export function registerWorkspaceIpc(db: Database, getWin: () => BrowserWindow | null): void { |
| 1636 | ipcMain.handle( |
| 1637 | 'snapshots:v1:workspace:pick', |
| 1638 | async (_e: unknown, raw: unknown): Promise<string | null> => { |
| 1639 | if (typeof raw !== 'object' || raw === null) { |
| 1640 | throw new CodesignError( |
| 1641 | 'snapshots:v1:workspace:pick expects an object payload', |
| 1642 | 'IPC_BAD_INPUT', |
| 1643 | ); |
| 1644 | } |
| 1645 | requireSchemaV1(raw as Record<string, unknown>, 'snapshots:v1:workspace:pick'); |
| 1646 | const win = getWin(); |
| 1647 | if (!win) { |
| 1648 | throw new CodesignError('Window not available', 'IPC_DB_ERROR'); |
| 1649 | } |
| 1650 | let result: Awaited<ReturnType<typeof dialog.showOpenDialog>>; |
| 1651 | try { |
| 1652 | result = await dialog.showOpenDialog(win, { properties: ['openDirectory'] }); |
| 1653 | } catch (cause) { |
| 1654 | throw new CodesignError('Failed to open folder picker dialog', 'IPC_DB_ERROR', { cause }); |
| 1655 | } |
| 1656 | if (result.canceled || result.filePaths.length === 0) { |
| 1657 | return null; |
| 1658 | } |
| 1659 | return result.filePaths[0] ?? null; |
| 1660 | }, |
| 1661 | ); |
| 1662 | |
| 1663 | ipcMain.handle( |
| 1664 | 'snapshots:v1:workspace:update', |
| 1665 | async (_e: unknown, raw: unknown): Promise<Design> => { |
| 1666 | if (typeof raw !== 'object' || raw === null) { |
| 1667 | throw new CodesignError( |
| 1668 | 'snapshots:v1:workspace:update expects an object payload', |
| 1669 | 'IPC_BAD_INPUT', |
| 1670 | ); |
| 1671 | } |
| 1672 | const r = raw as Record<string, unknown>; |
| 1673 | requireSchemaV1(r, 'snapshots:v1:workspace:update'); |
| 1674 | |
| 1675 | if (typeof r['designId'] !== 'string' || r['designId'].trim().length === 0) { |
| 1676 | throw new CodesignError('designId must be a non-empty string', 'IPC_BAD_INPUT'); |
| 1677 | } |
| 1678 | const workspacePath = r['workspacePath']; |
| 1679 | if (workspacePath === null) { |
| 1680 | throw new CodesignError('workspacePath cannot be null in v0.2', 'IPC_BAD_INPUT'); |
| 1681 | } |
| 1682 | if (typeof workspacePath !== 'string') { |
| 1683 | throw new CodesignError('workspacePath must be a string', 'IPC_BAD_INPUT'); |
| 1684 | } |
| 1685 | if (typeof r['migrateFiles'] !== 'boolean') { |
| 1686 | throw new CodesignError('migrateFiles must be a boolean', 'IPC_BAD_INPUT'); |
| 1687 | } |
| 1688 | |
| 1689 | try { |
| 1690 | const design = await bindWorkspace( |
| 1691 | db, |
| 1692 | r['designId'] as string, |
no test coverage detected