diff --git a/src/server/api/sync.ts b/src/server/api/sync.ts index d1475eb..e82bf6b 100644 --- a/src/server/api/sync.ts +++ b/src/server/api/sync.ts @@ -1,4 +1,4 @@ -import { APPS_DIR, allApps, emit, registerApp, reloadApp, removeApp, restartApp, startApp } from '$apps' +import { APPS_DIR, allApps, emit, registerApp, removeApp, restartApp, startApp } from '$apps' import { computeHash, generateManifest } from '../sync' import { loadGitignore } from '@gitignore' import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, unlinkSync, watch, writeFileSync } from 'fs' @@ -115,14 +115,25 @@ router.post('/apps/:app/reload', async c => { const appName = c.req.param('app') if (!appName) return c.json({ error: 'App name required' }, 400) - try { - await reloadApp(appName) - } catch (e) { - return c.json({ error: `Failed to reload app: ${e instanceof Error ? e.message : String(e)}` }, 500) - } - emit({ type: 'app:reload', app: appName }) + // Register new app or restart existing + const app = allApps().find(a => a.name === appName) + if (!app) { + // New app - register it + registerApp(appName) + } else if (app.state === 'running') { + // Existing app - restart it + try { + await restartApp(appName) + } catch (e) { + return c.json({ error: `Failed to restart app: ${e instanceof Error ? e.message : String(e)}` }, 500) + } + } else if (app.state === 'stopped' || app.state === 'invalid') { + // App not running - try to start it + startApp(appName) + } + return c.json({ ok: true }) }) diff --git a/src/server/apps.ts b/src/server/apps.ts index 5566008..bbeebb9 100644 --- a/src/server/apps.ts +++ b/src/server/apps.ts @@ -176,69 +176,6 @@ export function registerApp(dir: string) { } } -export async function reloadApp(dir: string) { - const app = _apps.get(dir) - if (!app) { - // New app — register it - registerApp(dir) - return - } - - // Re-read config from disk - const { pkg, error } = loadApp(dir) - const wasStatic = app.static - const nowStatic = !!pkg.toes?.static - - // Update cached metadata - app.icon = pkg.toes?.icon ?? DEFAULT_EMOJI - app.tool = pkg.toes?.tool - app.apps = pkg.toes?.apps - app.dashboard = pkg.toes?.dashboard - app.share = pkg.toes?.share - app.static = pkg.toes?.static - app.error = error - - if (error) { - // App is now invalid - if (app.state === 'running' || app.state === 'starting') { - stopApp(dir) - } - app.state = 'invalid' - update() - return - } - - if (nowStatic) { - // Stop process if transitioning from process-based to static - if (!wasStatic && (app.state === 'running' || app.state === 'starting')) { - stopApp(dir) - // Wait for stop - const maxWait = 10000 - const poll = 100 - let waited = 0 - while (_apps.get(dir)?.state !== 'stopped' && waited < maxWait) { - await new Promise(r => setTimeout(r, poll)) - waited += poll - } - } - // Mark as running (static apps are always "running") - app.state = 'running' - app.started = Date.now() - app.manuallyStopped = false - update() - publishApp(dir) - openTunnelIfEnabled(dir, SERVER_PORT) - return - } - - // Process-based app — restart it - if (app.state === 'running' || app.state === 'starting') { - await restartApp(dir) - } else { - startApp(dir) - } -} - export async function renameApp(oldName: string, newName: string): Promise<{ ok: boolean, error?: string }> { const app = _apps.get(oldName) if (!app) return { ok: false, error: 'App not found' } diff --git a/src/server/tunnels.ts b/src/server/tunnels.ts index d88ebdc..942a1dd 100644 --- a/src/server/tunnels.ts +++ b/src/server/tunnels.ts @@ -180,9 +180,6 @@ function openTunnel(appName: string, port: number, subdomain?: string, isReconne onRequest(req) { const app = getApp(appName) if (app?.tunnelUrl) req.headers['x-app-url'] = app.tunnelUrl - // Static apps are served by the main server via subdomain routing, - // so set the Host header so extractSubdomain() can identify the app - if (app?.static) req.headers['host'] = `${appName}.localhost` }, onOpen(assignedSubdomain) {