1- import { app , BrowserWindow } from 'electron' ;
1+ import { app , BrowserWindow , dialog , ipcMain } from 'electron' ;
22import path from 'node:path' ;
3+ import fs from 'node:fs' ;
34import started from 'electron-squirrel-startup' ;
5+ import { startBackendServer } from '../../backend/src/server.ts' ;
46
57// Handle creating/removing shortcuts on Windows when installing/uninstalling.
68if ( started ) {
79 app . quit ( ) ;
810}
911
12+ const appDataPath = app . getPath ( 'appData' ) ;
13+ const stableUserDataPath = path . join ( appDataPath , 'StarQuery' ) ;
14+ const legacyUserDataPaths = [
15+ path . join ( appDataPath , 'star-query' ) ,
16+ path . join ( appDataPath , 'Electron' ) ,
17+ ] ;
18+
19+ if ( ! fs . existsSync ( stableUserDataPath ) ) {
20+ const legacyPath = legacyUserDataPaths . find ( ( candidate ) => fs . existsSync ( candidate ) ) ;
21+ if ( legacyPath ) {
22+ fs . mkdirSync ( stableUserDataPath , { recursive : true } ) ;
23+ fs . cpSync ( legacyPath , stableUserDataPath , { recursive : true , force : false , errorOnExist : false } ) ;
24+ }
25+ }
26+
27+ app . setName ( 'StarQuery' ) ;
28+ app . setPath ( 'userData' , stableUserDataPath ) ;
29+
30+ const getDesktopConfigPath = ( ) => path . join ( app . getPath ( 'userData' ) , 'starquery-desktop.json' ) ;
31+ const getLocalMetaStorePath = ( ) => path . join ( app . getPath ( 'userData' ) , 'backend' , 'starquery-meta.sqlite' ) ;
32+
33+ let localBackend = null ;
34+ let isQuitting = false ;
35+
36+ const readDesktopConfig = ( ) => {
37+ const filePath = getDesktopConfigPath ( ) ;
38+
39+ if ( ! fs . existsSync ( filePath ) ) {
40+ return { } ;
41+ }
42+
43+ try {
44+ return JSON . parse ( fs . readFileSync ( filePath , 'utf-8' ) ) ;
45+ } catch {
46+ return { } ;
47+ }
48+ } ;
49+
50+ const writeDesktopConfig = ( config ) => {
51+ const filePath = getDesktopConfigPath ( ) ;
52+ fs . mkdirSync ( path . dirname ( filePath ) , { recursive : true } ) ;
53+ fs . writeFileSync ( filePath , JSON . stringify ( config , null , 2 ) ) ;
54+ } ;
55+
56+ const hasRunningLocalBackend = ( ) => Boolean ( localBackend ?. server ?. listening ) ;
57+
58+ const startLocalBackend = async ( ) => {
59+ if ( hasRunningLocalBackend ( ) ) {
60+ return localBackend ;
61+ }
62+
63+ if ( localBackend ) {
64+ try {
65+ await localBackend . close ( ) ;
66+ } catch ( error ) {
67+ console . error ( 'Failed to clean up stale local StarQuery backend' , error ) ;
68+ } finally {
69+ localBackend = null ;
70+ }
71+ }
72+
73+ localBackend = await startBackendServer ( {
74+ host : '127.0.0.1' ,
75+ port : 0 ,
76+ serverName : 'Local Computer' ,
77+ mode : 'local' ,
78+ metaStore : {
79+ driver : 'sqlite' ,
80+ sqlitePath : getLocalMetaStorePath ( ) ,
81+ } ,
82+ } ) ;
83+
84+ return localBackend ;
85+ } ;
86+
1087const createWindow = async ( ) => {
1188 // Create the browser window.
1289 const mainWindow = new BrowserWindow ( {
1390 icon : '../images/128x128.png' ,
14- width : 800 ,
15- height : 600 ,
91+ width : 1280 ,
92+ height : 720 ,
93+ ...( 'darwin' ? { vibrancy : 'sidebar' ,
94+ visualEffectState : 'active' ,
95+ transparent : true } : { } ) ,
96+
1697 webPreferences : {
1798 preload : path . join ( __dirname , 'preload.js' ) ,
1899 } ,
19- titleBarStyle : 'hidden'
100+ titleBarStyle : process . platform === 'darwin' ? 'hiddenInset' : 'hidden'
101+ } ) ;
102+
103+ mainWindow . webContents . on ( "did-finish-load" , ( ) => {
104+ const electronClasses = [ 'electron' ] ;
105+ if ( process . platform === 'darwin' ) {
106+ electronClasses . push ( 'electron-mac' ) ;
107+ }
108+
109+ mainWindow . webContents . executeJavaScript ( `
110+ document.documentElement.classList.add(${ electronClasses . map ( ( value ) => JSON . stringify ( value ) ) . join ( ', ' ) } );
111+ ` ) ;
20112 } ) ;
21113
22114 // and load the index.html of the app.
23115 if ( MAIN_WINDOW_VITE_DEV_SERVER_URL ) {
24- mainWindow . loadURL ( /* MAIN_WINDOW_VITE_DEV_SERVER_URL*/ 'http://localhost:5173/' ) ;
116+ await mainWindow . loadURL ( MAIN_WINDOW_VITE_DEV_SERVER_URL ) ;
25117 } else {
26- mainWindow . loadFile ( path . join ( __dirname , `../renderer/${ MAIN_WINDOW_VITE_NAME } /index.html` ) ) ;
118+ await mainWindow . loadFile ( path . join ( __dirname , `../renderer/${ MAIN_WINDOW_VITE_NAME } /index.html` ) ) ;
27119 }
28120
29- mainWindow . webContents . on ( "did-finish-load" , ( ) => {
30- mainWindow . webContents . executeJavaScript ( `
31- document.documentElement.classList.add("electron");
32- ` ) ;
33- } ) ;
34-
35121 // Open the DevTools.
36122 //mainWindow.webContents.openDevTools();
37123} ;
38124
39- app . whenReady ( ) . then ( ( ) => {
40- createWindow ( ) ;
125+ app . whenReady ( ) . then ( async ( ) => {
126+ try {
127+ await startLocalBackend ( ) ;
128+ } catch ( error ) {
129+ console . error ( 'Failed to start local StarQuery backend' , error ) ;
130+ }
131+
132+ ipcMain . handle ( 'starquery:desktop-config:get' , ( ) => readDesktopConfig ( ) ) ;
133+ ipcMain . handle ( 'starquery:desktop-config:set' , ( _event , config ) => {
134+ writeDesktopConfig ( config ) ;
135+ return { ok : true } ;
136+ } ) ;
137+ ipcMain . handle ( 'starquery:local-server:url' , async ( ) => {
138+ try {
139+ await startLocalBackend ( ) ;
140+ } catch ( error ) {
141+ console . error ( 'Failed to provide local backend URL' , error ) ;
142+ return null ;
143+ }
144+
145+ return localBackend ?. url ?? null ;
146+ } ) ;
147+ ipcMain . handle ( 'starquery:sqlite-file:pick' , async ( ) => {
148+ const result = await dialog . showOpenDialog ( {
149+ properties : [ 'openFile' ] ,
150+ filters : [
151+ { name : 'SQLite Databases' , extensions : [ 'sqlite' , 'sqlite3' , 'db' , 'db3' ] } ,
152+ { name : 'All Files' , extensions : [ '*' ] } ,
153+ ] ,
154+ } ) ;
155+
156+ return result . canceled ? null : ( result . filePaths [ 0 ] ?? null ) ;
157+ } ) ;
158+
159+ await createWindow ( ) ;
41160 app . on ( 'activate' , ( ) => {
42161 if ( BrowserWindow . getAllWindows ( ) . length === 0 ) {
43- createWindow ( ) ;
162+ void createWindow ( ) ;
44163 }
45164 } ) ;
46165} ) ;
47166
167+ app . on ( 'before-quit' , ( event ) => {
168+ if ( isQuitting ) {
169+ return ;
170+ }
171+
172+ isQuitting = true ;
173+ event . preventDefault ( ) ;
174+
175+ Promise . resolve ( localBackend ?. close ( ) )
176+ . catch ( ( error ) => {
177+ console . error ( 'Failed to stop local StarQuery backend' , error ) ;
178+ } )
179+ . finally ( ( ) => {
180+ localBackend = null ;
181+ app . quit ( ) ;
182+ } ) ;
183+ } ) ;
184+
48185app . on ( 'window-all-closed' , ( ) => {
49186 if ( process . platform !== 'darwin' ) {
50187 app . quit ( ) ;
51188 }
52- } ) ;
189+ } ) ;
0 commit comments