Reshape desktop bootstrap into independent services

HostRuntime self-boots via boot() and emits state through existing
subscribeAll plumbing. DaemonStartService runs in parallel: on success
it upserts the connection, which HostRuntime's syncHosts already wires
into a controller; on failure it emits an error.

The bootstrap no longer awaits daemon-start before letting saved-host
controllers connect. index.tsx resolves the redirect from
useEarliestOnlineHostServerId + useDaemonStartLastError subscriptions,
not from a procedural promise. The splash error is derived state:
splashError = !anyOnlineHostServerId ? daemonStartError : null. Retry
calls only DaemonStartService.start().

Deletes initializeHostRuntime, setupDesktopManagedConnection,
addConnectionFromListenAndWaitForOnline, bootstrapDesktop on the store,
waitForAnyConnectionOnline (now unused in production), and the
phase enum. Net -623 lines.
This commit is contained in:
Mohamed Boudra
2026-04-27 16:36:07 +07:00
parent 88f382cad3
commit 40ce317ac2
10 changed files with 720 additions and 1006 deletions

View File

@@ -0,0 +1,127 @@
import { startDesktopDaemon, type DesktopDaemonStatus } from "@/desktop/daemon/desktop-daemon";
import { connectionFromListen } from "@/types/host-connection";
import type { HostRuntimeStore } from "@/runtime/host-runtime";
export type DaemonStartResult = { ok: true } | { ok: false; error: string };
export interface DaemonStartServiceDeps {
store: Pick<HostRuntimeStore, "upsertConnectionFromListen">;
startDesktopDaemon?: () => Promise<DesktopDaemonStatus>;
}
export class DaemonStartService {
private readonly store: Pick<HostRuntimeStore, "upsertConnectionFromListen">;
private readonly invokeStartDesktopDaemon: () => Promise<DesktopDaemonStatus>;
private readonly listeners = new Set<() => void>();
private lastError: string | null = null;
private inFlightCount = 0;
constructor(deps: DaemonStartServiceDeps) {
this.store = deps.store;
this.invokeStartDesktopDaemon = deps.startDesktopDaemon ?? startDesktopDaemon;
}
async start(): Promise<DaemonStartResult> {
this.beginRequest();
try {
const daemon = await this.invokeStartDesktopDaemon();
const listenAddress = daemon.listen?.trim() ?? "";
const serverId = daemon.serverId.trim();
if (!listenAddress) {
return this.fail("Desktop daemon did not return a listen address.");
}
if (!serverId) {
return this.fail("Desktop daemon did not return a server id.");
}
if (!connectionFromListen(listenAddress)) {
return this.fail(`Desktop daemon returned an unsupported listen address: ${listenAddress}`);
}
await this.store.upsertConnectionFromListen({
listenAddress,
serverId,
hostname: daemon.hostname,
});
return { ok: true };
} catch (error) {
return this.fail(error instanceof Error ? error.message : String(error));
} finally {
this.endRequest();
}
}
getLastError(): string | null {
return this.lastError;
}
isRunning(): boolean {
return this.inFlightCount > 0;
}
subscribe(listener: () => void): () => void {
this.listeners.add(listener);
return () => {
this.listeners.delete(listener);
};
}
private fail(message: string): DaemonStartResult {
this.setLastError(message);
return { ok: false, error: message };
}
private setLastError(value: string | null): void {
if (this.lastError === value) {
return;
}
this.lastError = value;
this.notify();
}
private beginRequest(): void {
const becameRunning = this.inFlightCount === 0;
this.inFlightCount += 1;
const errorChanged = this.lastError !== null;
this.lastError = null;
if (becameRunning || errorChanged) {
this.notify();
}
}
private endRequest(): void {
this.inFlightCount = Math.max(0, this.inFlightCount - 1);
if (this.inFlightCount === 0) {
this.notify();
}
}
private notify(): void {
for (const listener of this.listeners) {
listener();
}
}
}
let singletonDaemonStartService: DaemonStartService | null = null;
const DAEMON_START_SERVICE_GLOBAL_KEY = "__paseoDaemonStartService";
type DaemonStartServiceGlobal = typeof globalThis & {
[DAEMON_START_SERVICE_GLOBAL_KEY]?: DaemonStartService;
};
export function getDaemonStartService(deps: DaemonStartServiceDeps): DaemonStartService {
if (singletonDaemonStartService) {
return singletonDaemonStartService;
}
const runtimeGlobal = globalThis as DaemonStartServiceGlobal;
if (runtimeGlobal[DAEMON_START_SERVICE_GLOBAL_KEY]) {
singletonDaemonStartService = runtimeGlobal[DAEMON_START_SERVICE_GLOBAL_KEY] ?? null;
if (singletonDaemonStartService) {
return singletonDaemonStartService;
}
}
singletonDaemonStartService = new DaemonStartService(deps);
runtimeGlobal[DAEMON_START_SERVICE_GLOBAL_KEY] = singletonDaemonStartService;
return singletonDaemonStartService;
}