refactor: Modularize Electron main process into single-responsibility components

Extract the monolithic main.ts (~1000 lines) into focused modules:

- electron/constants.ts - Window sizing, port defaults, filenames
- electron/state.ts - Shared state container
- electron/utils/ - Port availability and icon utilities
- electron/security/ - API key management
- electron/windows/ - Window bounds and main window creation
- electron/server/ - Backend and static server management
- electron/ipc/ - IPC handlers with shared channel constants

Benefits:
- Improved testability with isolated modules
- Better discoverability and maintainability
- Single source of truth for IPC channels (used by both main and preload)
- Clear separation of concerns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Shirone
2026-01-25 20:43:08 +01:00
parent 2f883bad20
commit 615823652c
20 changed files with 1221 additions and 847 deletions

View File

@@ -0,0 +1,58 @@
/**
* API key management
*
* Handles generation, storage, and retrieval of the API key for CSRF protection.
* Uses centralized electronUserData methods for path validation.
*/
import crypto from 'crypto';
import {
electronUserDataExists,
electronUserDataReadFileSync,
electronUserDataWriteFileSync,
} from '@automaker/platform';
import { createLogger } from '@automaker/utils/logger';
import { API_KEY_FILENAME } from '../constants';
import { state } from '../state';
const logger = createLogger('ApiKeyManager');
/**
* Ensure an API key exists - load from file or generate new one.
* This key is passed to the server for CSRF protection.
* Uses centralized electronUserData methods for path validation.
*/
export function ensureApiKey(): string {
try {
if (electronUserDataExists(API_KEY_FILENAME)) {
const key = electronUserDataReadFileSync(API_KEY_FILENAME).trim();
if (key) {
state.apiKey = key;
logger.info('Loaded existing API key');
return state.apiKey;
}
}
} catch (error) {
logger.warn('Error reading API key:', error);
}
// Generate new key
state.apiKey = crypto.randomUUID();
try {
electronUserDataWriteFileSync(API_KEY_FILENAME, state.apiKey, {
encoding: 'utf-8',
mode: 0o600,
});
logger.info('Generated new API key');
} catch (error) {
logger.error('Failed to save API key:', error);
}
return state.apiKey;
}
/**
* Get the current API key
*/
export function getApiKey(): string | null {
return state.apiKey;
}