Files
makelore/electron/utils/store.ts
brother7 518d7ab4cd feat: 对接设计 Agent Gateway WebSocket
需求:服务端统一 Agent Gateway 将设计任务状态流切换为 WebSocket,客户端需要实时展示生成任务并支持断线恢复。

实现:Electron Main 管理 Session、一次性 Ticket、WebSocket 心跳与游标续传,按关闭码回收会话;Renderer 继续通过本机 Host API 的 SSE 投影接收任务事件,并保留 REST 降级同步。

验证:typecheck、变更文件 ESLint、37 个聚焦测试及 build:vite 通过。
2026-08-02 20:15:37 +08:00

202 lines
5.1 KiB
TypeScript

/**
* Persistent Storage
* Electron-store wrapper for application settings
*/
import { app } from 'electron';
import { randomUUID } from 'node:crypto';
import { resolveSupportedLanguage } from '../../shared/language';
// Lazy-load electron-store (ESM module)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let settingsStoreInstance: any = null;
/**
* Application settings schema
*/
export interface AppSettings {
// General
theme: 'light' | 'dark' | 'system';
language: string;
startMinimized: boolean;
launchAtStartup: boolean;
telemetryEnabled: boolean;
machineId: string;
agentGatewaySessionClientIds: Record<string, string>;
hasReportedInstall: boolean;
proxyEnabled: boolean;
proxyServer: string;
proxyHttpServer: string;
proxyHttpsServer: string;
proxyAllServer: string;
proxyBypassRules: string;
// Update
updateChannel: 'stable' | 'beta' | 'dev';
autoCheckUpdate: boolean;
autoDownloadUpdate: boolean;
skippedVersions: string[];
// UI State
sidebarCollapsed: boolean;
devModeUnlocked: boolean;
// Presets
selectedBundles: string[];
enabledSkills: string[];
disabledSkills: string[];
}
/**
* Default settings
*/
function getSystemLocale(): string {
const preferredLanguages = typeof app.getPreferredSystemLanguages === 'function'
? app.getPreferredSystemLanguages()
: [];
return preferredLanguages[0]
|| (typeof app.getLocale === 'function' ? app.getLocale() : '')
|| Intl.DateTimeFormat().resolvedOptions().locale
|| 'en';
}
function createDefaultSettings(): AppSettings {
return {
// General
theme: 'system',
language: resolveSupportedLanguage(getSystemLocale()),
startMinimized: false,
launchAtStartup: false,
telemetryEnabled: true,
machineId: '',
agentGatewaySessionClientIds: {},
hasReportedInstall: false,
proxyEnabled: false,
proxyServer: '',
proxyHttpServer: '',
proxyHttpsServer: '',
proxyAllServer: '',
proxyBypassRules: '<local>;localhost;127.0.0.1;::1',
// Update
updateChannel: 'stable',
autoCheckUpdate: true,
autoDownloadUpdate: false,
skippedVersions: [],
// UI State
sidebarCollapsed: false,
devModeUnlocked: false,
// Presets
selectedBundles: ['productivity', 'developer'],
enabledSkills: [],
disabledSkills: [],
};
}
/**
* Get the settings store instance (lazy initialization)
*/
async function getSettingsStore() {
if (!settingsStoreInstance) {
const Store = (await import('electron-store')).default;
settingsStoreInstance = new Store<AppSettings>({
name: 'settings',
defaults: createDefaultSettings(),
});
}
return settingsStoreInstance;
}
/**
* Get a setting value
*/
export async function getSetting<K extends keyof AppSettings>(key: K): Promise<AppSettings[K]> {
const store = await getSettingsStore();
return store.get(key);
}
/**
* Set a setting value
*/
export async function setSetting<K extends keyof AppSettings>(
key: K,
value: AppSettings[K]
): Promise<void> {
const store = await getSettingsStore();
store.set(key, value);
}
let agentGatewaySessionIdMutation: Promise<void> = Promise.resolve();
async function mutateAgentGatewaySessionClientIds<T>(
mutation: (current: Record<string, string>) => Promise<T> | T,
): Promise<T> {
const result = agentGatewaySessionIdMutation.then(async () => {
const current = await getSetting('agentGatewaySessionClientIds');
return await mutation({ ...current });
});
agentGatewaySessionIdMutation = result.then(() => undefined, () => undefined);
return await result;
}
export function getOrCreateAgentGatewaySessionClientId(workspaceId: string): Promise<string> {
return mutateAgentGatewaySessionClientIds(async (current) => {
const existing = current[workspaceId]?.trim();
if (existing) return existing;
const created = `design-stream-${randomUUID()}`;
current[workspaceId] = created;
await setSetting('agentGatewaySessionClientIds', current);
return created;
});
}
export function rotateAgentGatewaySessionClientId(workspaceId: string): Promise<string> {
return mutateAgentGatewaySessionClientIds(async (current) => {
const created = `design-stream-${randomUUID()}`;
current[workspaceId] = created;
await setSetting('agentGatewaySessionClientIds', current);
return created;
});
}
/**
* Get all settings
*/
export async function getAllSettings(): Promise<AppSettings> {
const store = await getSettingsStore();
return store.store;
}
/**
* Reset settings to defaults
*/
export async function resetSettings(): Promise<void> {
const store = await getSettingsStore();
store.clear();
}
/**
* Export settings to JSON
*/
export async function exportSettings(): Promise<string> {
const store = await getSettingsStore();
return JSON.stringify(store.store, null, 2);
}
/**
* Import settings from JSON
*/
export async function importSettings(json: string): Promise<void> {
try {
const settings = JSON.parse(json);
const store = await getSettingsStore();
store.set(settings);
} catch {
throw new Error('Invalid settings JSON');
}
}