import React, { useMemo, useSyncExternalStore } from "react";
import type { AppManifest } from "../kernel/types";
import { makeOSApi } from "../kernel/sdk";
import {
AppErrorBoundary,
getCompiled,
} from "../kernel/appRuntime";
import { onRuntimeVersionChange, runtimeVersionOf } from "../kernel/store";
// Renders a single app instance inside a window body.
// Built-in apps render their component directly; generated apps are compiled.
export function AppHost({ app, windowId }: { app: AppManifest; windowId: string }) {
const version = useSyncExternalStore(
onRuntimeVersionChange,
() => runtimeVersionOf(app.id)
);
const os = useMemo(() => makeOSApi(app.id, windowId), [app.id, windowId]);
// Only meaningful for generated apps; cheap no-op for built-ins (cached).
const compiled = useMemo(
() => (app.builtin ? null : getCompiled(app, version)),
[app, version]
);
if (app.builtin && app.component) {
const C = app.component;
return (
);
}
// generated app
if (!compiled) return null;
if (compiled.error) {
return (
);
}
const Generated = compiled.Component!;
return (
);
}
function CompileError({ message }: { message: string }): React.ReactElement {
// Thrown so the error boundary picks it up and offers self-heal.
throw new Error("Compile error: " + message);
}