feat(console-web): replace TanStack UI with Solid host pages

- move the management frontend under the wasmeld-console crate\n- use a persistent Host shell with disposable iframe page documents\n- version Host/Page postMessage state and command contracts\n- migrate runtime, service, WIT, invocation, and settings workflows\n- add Tailwind CSS v4, responsive layouts, and Host-owned dialogs\n- emit a dependency-free PWA worker with API cache exclusions\n- remove the superseded root TanStack Start application
This commit is contained in:
Maofeng
2026-07-30 09:21:55 +08:00
parent 4e32a1246b
commit 90742837fc
49 changed files with 3996 additions and 5648 deletions
@@ -0,0 +1,95 @@
import type { BackendSnapshot } from "../lib/api";
import type { ConnectionState, View } from "../lib/model";
export const SDK_CHANNEL = "wasmeld-console";
/**
* Compatibility version for the same-origin Host/Page document protocol.
*
* Additive optional messages may keep the version. Removing a field or
* changing its meaning requires a version bump and an atomic Host/Page
* release, which is naturally provided by the embedded Console binary.
*/
export const SDK_VERSION = 1;
export type RuntimeAction = "start" | "stop" | "restart";
export type ServiceAction = "start" | "stop" | "restart";
export type HostSharedState = {
// This is a serializable snapshot, never a Solid signal crossing realms.
view: View;
snapshot: BackendSnapshot | null;
connection: ConnectionState;
query: string;
apiBase: string;
runtimeAction: RuntimeAction | null;
serviceAction: string | null;
deploymentAction: string | null;
};
export type PageCommand =
| { type: "refresh" }
| { type: "navigate"; view: View }
| { type: "open-register" }
| { type: "open-wit-publish" }
| { type: "open-invoke"; serviceKey: string }
| { type: "open-activate"; serviceKey: string }
| { type: "runtime-action"; action: RuntimeAction }
| { type: "service-action"; serviceKey: string; action: ServiceAction }
| { type: "save-api-base"; value: string };
export type PageMessage =
| {
channel: typeof SDK_CHANNEL;
version: typeof SDK_VERSION;
source: "page";
type: "ready";
view: View;
}
| {
channel: typeof SDK_CHANNEL;
version: typeof SDK_VERSION;
source: "page";
type: "command";
view: View;
command: PageCommand;
};
export type HostMessage =
| {
channel: typeof SDK_CHANNEL;
version: typeof SDK_VERSION;
source: "host";
type: "state";
state: HostSharedState;
}
| {
channel: typeof SDK_CHANNEL;
version: typeof SDK_VERSION;
source: "host";
type: "dispose";
};
export function isPageMessage(value: unknown): value is PageMessage {
if (!isRecord(value)) return false;
return (
value.channel === SDK_CHANNEL &&
value.version === SDK_VERSION &&
value.source === "page" &&
(value.type === "ready" || value.type === "command")
);
}
export function isHostMessage(value: unknown): value is HostMessage {
if (!isRecord(value)) return false;
return (
value.channel === SDK_CHANNEL &&
value.version === SDK_VERSION &&
value.source === "host" &&
(value.type === "state" || value.type === "dispose")
);
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}