@@ -210,38 +210,45 @@ app.whenReady().then(async () => {
210210 Menu . setApplicationMenu ( null ) ;
211211
212212 // Register phtauri:// protocol for serving Phoenix files
213- // In dev: serves from ../phoenix/ repo
214- // In packaged: would need different handling (but typically uses https:// in production)
215- if ( ! app . isPackaged ) {
216- const phoenixRepoPath = path . resolve ( __dirname , '..' , '..' , 'phoenix' ) ;
217-
218- protocol . handle ( 'phtauri' , ( request ) => {
219- try {
220- const url = new URL ( request . url ) ;
221- // phtauri://localhost/src/index.html -> ../phoenix/src/index.html
222- let requestedPath = decodeURIComponent ( url . pathname ) ;
223-
224- // Serve index.html for directory requests
225- if ( requestedPath . endsWith ( '/' ) ) {
226- requestedPath += 'index.html' ;
227- }
228-
229- const filePath = path . join ( phoenixRepoPath , requestedPath ) ;
230- const normalizedFilePath = path . normalize ( filePath ) ;
231-
232- // Security: Ensure path is under phoenix repo (prevent directory traversal)
233- if ( ! normalizedFilePath . startsWith ( phoenixRepoPath ) ) {
234- console . error ( 'phtauri access denied - path not under phoenix repo:' , requestedPath ) ;
235- return new Response ( 'Access denied' , { status : 403 } ) ;
236- }
237-
238- return net . fetch ( `file://${ normalizedFilePath } ` ) ;
239- } catch ( err ) {
240- console . error ( 'phtauri protocol error:' , err ) ;
241- return new Response ( 'Not found' , { status : 404 } ) ;
213+ // In dev: serves from ../phoenix/ repo (phtauri://localhost/src/ -> ../phoenix/src/)
214+ // In packaged: serves from resources/phoenix-dist/ (phtauri://localhost/src/ -> phoenix-dist/)
215+ const phoenixBasePath = app . isPackaged
216+ ? path . join ( process . resourcesPath , 'phoenix-dist' )
217+ : path . resolve ( __dirname , '..' , '..' , 'phoenix' , 'src' ) ;
218+
219+ protocol . handle ( 'phtauri' , ( request ) => {
220+ try {
221+ const url = new URL ( request . url ) ;
222+ // phtauri://localhost/src/index.html -> strip /src prefix
223+ let requestedPath = decodeURIComponent ( url . pathname ) ;
224+
225+ // Strip /src/ prefix since phoenix-dist already contains src contents
226+ if ( requestedPath . startsWith ( '/src/' ) ) {
227+ requestedPath = requestedPath . substring ( 4 ) ; // Remove '/src'
228+ } else if ( requestedPath === '/src' ) {
229+ requestedPath = '/' ;
242230 }
243- } ) ;
244- }
231+
232+ // Serve index.html for directory requests
233+ if ( requestedPath . endsWith ( '/' ) ) {
234+ requestedPath += 'index.html' ;
235+ }
236+
237+ const filePath = path . join ( phoenixBasePath , requestedPath ) ;
238+ const normalizedFilePath = path . normalize ( filePath ) ;
239+
240+ // Security: Ensure path is under phoenix base (prevent directory traversal)
241+ if ( ! normalizedFilePath . startsWith ( phoenixBasePath ) ) {
242+ console . error ( 'phtauri access denied - path not under phoenix base:' , requestedPath ) ;
243+ return new Response ( 'Access denied' , { status : 403 } ) ;
244+ }
245+
246+ return net . fetch ( `file://${ normalizedFilePath } ` ) ;
247+ } catch ( err ) {
248+ console . error ( 'phtauri protocol error:' , err ) ;
249+ return new Response ( 'Not found' , { status : 404 } ) ;
250+ }
251+ } ) ;
245252
246253 // Register asset:// protocol for serving local files from appLocalData/assets/
247254 const appDataDir = getAppDataDir ( ) ;
0 commit comments