11#!/usr/bin/env node
22
33import { spawn , spawnSync } from "child_process" ;
4- import open from "open" ;
5- import path from "path" ;
6- import fs from "fs" ;
7- import { fileURLToPath } from "url" ;
84import { select } from "@inquirer/prompts" ;
5+ import open from "open" ;
96
10- const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
11-
12- const FRONTEND_PORT = 4173 ;
137const REST_PORT = 5000 ;
14-
15- /* ---------------------------
16- PRE-FLIGHT CHECKS
17- ---------------------------- */
8+ const FRONTEND_URL = "https://aiidateam.github.io/aiida-explorer/" ;
189
1910function fail ( msg ) {
2011 console . error ( `\n${ msg } \n` ) ;
2112 process . exit ( 1 ) ;
2213}
2314
24- function checkVerdi ( ) {
25- const res = spawnSync ( "verdi" , [ "--help" ] , { encoding : "utf-8" } ) ;
15+ /* ---------------------------
16+ CHECKS
17+ ---------------------------- */
2618
27- if ( res . error ) {
28- fail ( ' "verdi" not found. Is AiiDA installed and activated?' ) ;
29- }
19+ function checkVerdi ( ) {
20+ const res = spawnSync ( "verdi" , [ "--help" ] ) ;
21+ if ( res . error ) fail ( '"verdi" not found.' ) ;
3022}
3123
3224function checkRestApiDeps ( ) {
33- const res = spawnSync (
34- "python" ,
35- [ "-c" , "from aiida.restapi.run_api import run_api" ] ,
36- { encoding : "utf-8" } ,
37- ) ;
25+ const res = spawnSync ( "python" , [
26+ "-c" ,
27+ "from aiida.restapi.run_api import run_api" ,
28+ ] ) ;
3829
3930 if ( res . status !== 0 ) {
40- fail (
41- "Missing AiiDA REST API dependencies.\n\nFix:\n pip install aiida-core[rest-api]" ,
42- ) ;
43- }
44- }
45-
46- function checkFrontend ( ) {
47- const distPath = path . join ( __dirname , "dist" ) ;
48-
49- if ( ! fs . existsSync ( distPath ) ) {
50- fail ( 'Frontend build missing. Expected "dist/" in package.' ) ;
31+ fail ( "Missing AiiDA REST API dependencies." ) ;
5132 }
5233}
5334
5435/* ---------------------------
55- PROFILE SELECTION
36+ PROFILES
5637---------------------------- */
5738
5839function getProfiles ( ) {
5940 const res = spawnSync ( "verdi" , [ "profile" , "list" ] , {
6041 encoding : "utf-8" ,
6142 } ) ;
6243
63- if ( res . status !== 0 ) {
64- fail ( "Failed to fetch AiiDA profiles" ) ;
65- }
66-
67- const lines = res . stdout . split ( "\n" ) ;
44+ if ( res . status !== 0 ) fail ( "Failed to list profiles." ) ;
6845
6946 let active = null ;
7047
71- const profiles = lines
48+ const profiles = res . stdout
49+ . split ( "\n" )
7250 . map ( ( l ) => l . trim ( ) )
73- . filter ( ( l ) => l && ! l . startsWith ( "Report" ) )
51+ . filter ( Boolean )
7452 . map ( ( l ) => {
7553 if ( l . startsWith ( "*" ) ) {
7654 active = l . replace ( / ^ \* \s * / , "" ) ;
7755 return active ;
7856 }
79- return l . replace ( / ^ \* \s * / , "" ) ;
80- } )
81- . filter ( Boolean ) ;
57+ return l ;
58+ } ) ;
8259
8360 return { profiles, active } ;
8461}
8562
8663async function selectProfile ( profiles , active ) {
87- return await select ( {
64+ return select ( {
8865 message : "Select AiiDA profile" ,
8966 choices : profiles . map ( ( p ) => ( {
9067 name : p ,
@@ -96,41 +73,34 @@ async function selectProfile(profiles, active) {
9673}
9774
9875/* ---------------------------
99- STARTUP
76+ REST API
10077---------------------------- */
10178
102- let restProc = null ;
103- let frontendProc = null ;
104-
10579function startRestApi ( profile ) {
106- console . log ( `Starting AiiDA REST API (profile: ${ profile } )...` ) ;
80+ console . log ( `Starting REST API (${ profile } )...` ) ;
10781
108- const proc = spawn ( "verdi" , [ "-p" , profile , "restapi" , "--port" , REST_PORT ] , {
82+ return spawn ( "verdi" , [ "-p" , profile , "restapi" , "--port" , REST_PORT ] , {
10983 stdio : "inherit" ,
11084 } ) ;
111-
112- proc . on ( "exit" , ( code ) => {
113- console . log ( `\nREST API exited with code ${ code } ` ) ;
114- } ) ;
115-
116- return proc ;
11785}
11886
119- function startFrontend ( ) {
120- console . log ( "🌐 Starting frontend (Vite preview)..." ) ;
87+ /* ---------------------------
88+ WAIT FOR API
89+ ---------------------------- */
12190
122- const viteBin = path . join ( __dirname , "node_modules" , ".bin" , "vite" ) ;
91+ async function waitForApi ( ) {
92+ const url = `http://localhost:${ REST_PORT } /api/v4` ;
12393
124- const proc = spawn ( viteBin , [ "preview" , "--port" , FRONTEND_PORT ] , {
125- cwd : __dirname ,
126- stdio : "inherit" ,
127- } ) ;
94+ for ( let i = 0 ; i < 30 ; i ++ ) {
95+ try {
96+ const res = await fetch ( url ) ;
97+ if ( res . ok ) return url ;
98+ } catch { }
12899
129- proc . on ( "exit" , ( code ) => {
130- console . log ( `\nFrontend exited with code ${ code } ` ) ;
131- } ) ;
100+ await new Promise ( ( r ) => setTimeout ( r , 1000 ) ) ;
101+ }
132102
133- return proc ;
103+ fail ( "REST API did not start in time." ) ;
134104}
135105
136106/* ---------------------------
@@ -140,31 +110,22 @@ function startFrontend() {
140110async function main ( ) {
141111 checkVerdi ( ) ;
142112 checkRestApiDeps ( ) ;
143- checkFrontend ( ) ;
144113
145114 const { profiles, active } = getProfiles ( ) ;
146115 const selectedProfile = await selectProfile ( profiles , active ) ;
147116
148- restProc = startRestApi ( selectedProfile ) ;
149- frontendProc = startFrontend ( ) ;
117+ const restProc = startRestApi ( selectedProfile ) ;
150118
151- setTimeout ( ( ) => {
152- const apiUrl = `http://localhost:${ REST_PORT } /api/v4` ;
119+ const apiUrl = await waitForApi ( ) ;
153120
154- const url =
155- `http://localhost:${ FRONTEND_PORT } /` +
156- `?api_url=${ encodeURIComponent ( apiUrl ) } ` ;
121+ const frontend = FRONTEND_URL + `?api_url=${ encodeURIComponent ( apiUrl ) } ` ;
157122
158- console . log ( "\nOpening browser...\n" ) ;
159- open ( url ) ;
160- } , 5000 ) ;
123+ console . log ( "\nOpening browser..." ) ;
124+ await open ( frontend ) ;
161125
162126 function shutdown ( ) {
163127 console . log ( "\nShutting down..." ) ;
164-
165- if ( restProc ) restProc . kill ( "SIGTERM" ) ;
166- if ( frontendProc ) frontendProc . kill ( "SIGTERM" ) ;
167-
128+ restProc . kill ( "SIGTERM" ) ;
168129 process . exit ( 0 ) ;
169130 }
170131
0 commit comments