Files
wasmeld/crates/wasmeld-console/web/src/sdk/protocol.ts
T

111 lines
3.3 KiB
TypeScript
Raw Normal View History

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;
}