9ff3223c44
Declare navigation, page metadata, lazy loaders, and keep-alive policy in one registry. Retain primary iframe pages until a continuous inactive TTL expires and expose typed show, hide, and unload events through the Page SDK. Move business-aware components out of the UI primitive directory, migrate views and Host dialogs to variant primitives and local Tailwind classes, and remove the global component style layer. Keep native dialogs inside the overlay flex context so they remain centered. Cover iframe expiration, lifecycle dispatch, UI dependency direction, and global style ownership with focused tests.
111 lines
3.3 KiB
TypeScript
111 lines
3.3 KiB
TypeScript
import type { BackendSnapshot } from "../lib/api";
|
|
import type { ConnectionState } from "../lib/model";
|
|
import type { View } from "../pages/registry";
|
|
|
|
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 PageLifecyclePhase = "activate" | "deactivate" | "dispose";
|
|
|
|
/**
|
|
* Control-plane state shared unconditionally between same-origin Host tabs.
|
|
*
|
|
* Navigation, search, dialogs, notifications and iframe caches are excluded:
|
|
* those values describe one browser tab rather than the Wasmeld runtime.
|
|
*/
|
|
export type HostGlobalState = {
|
|
snapshot: BackendSnapshot | null;
|
|
connection: ConnectionState;
|
|
apiBase: string;
|
|
runtimeAction: RuntimeAction | null;
|
|
serviceAction: string | null;
|
|
deploymentAction: string | null;
|
|
};
|
|
|
|
export type HostSharedState = HostGlobalState & {
|
|
// This is a serializable snapshot, never a Solid signal crossing realms.
|
|
view: View;
|
|
query: string;
|
|
};
|
|
|
|
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: "lifecycle";
|
|
phase: PageLifecyclePhase;
|
|
};
|
|
|
|
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;
|
|
if (value.channel !== SDK_CHANNEL || value.version !== SDK_VERSION || value.source !== "host") {
|
|
return false;
|
|
}
|
|
if (value.type === "state") return isRecord(value.state);
|
|
return value.type === "lifecycle" && isPageLifecyclePhase(value.phase);
|
|
}
|
|
|
|
function isPageLifecyclePhase(value: unknown): value is PageLifecyclePhase {
|
|
return value === "activate" || value === "deactivate" || value === "dispose";
|
|
}
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null;
|
|
}
|