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 { return typeof value === "object" && value !== null; }