1975 lines
50 KiB
TypeScript
1975 lines
50 KiB
TypeScript
export const CONTROL_PLANE_DEFAULT_HOST = "127.0.0.1";
|
|
export const CONTROL_PLANE_DEFAULT_PORT = 6246;
|
|
export const CONTROL_PLANE_DEFAULT_URL = `http://${CONTROL_PLANE_DEFAULT_HOST}:${CONTROL_PLANE_DEFAULT_PORT}`;
|
|
|
|
export const CONTROL_PLANE_ROUTES = {
|
|
run: "/run",
|
|
status: "/status",
|
|
check: "/check",
|
|
cutover: "/cutover",
|
|
clearState: "/clear-state",
|
|
describe: "/describe",
|
|
logs: "/logs",
|
|
errors: "/errors",
|
|
devices: "/devices",
|
|
deviceAssign: "/devices/assign",
|
|
deviceAssignLive: "/devices/assign-live",
|
|
deviceRename: "/devices/rename",
|
|
deviceIdentify: "/devices/identify",
|
|
deviceStopIdentify: "/devices/stop-identify",
|
|
deviceRemove: "/devices/remove",
|
|
deviceSession: "/device/session",
|
|
deviceSocket: "/device-ws",
|
|
replEval: "/repl/eval",
|
|
replClose: "/repl/close",
|
|
browserSocket: "/ws",
|
|
} as const;
|
|
|
|
export type ControlPlaneRunRequest = {
|
|
target: string;
|
|
};
|
|
|
|
export type ControlPlaneCheckRequest = {
|
|
packageName: string;
|
|
rev: string;
|
|
};
|
|
|
|
export type ControlPlaneCutoverRequest = {
|
|
targets: string[];
|
|
};
|
|
|
|
export type ControlPlaneClearStateRequest = {
|
|
packageName: string;
|
|
recursive?: boolean;
|
|
};
|
|
|
|
export type ControlPlaneDescribeRequest = {
|
|
packageName: string;
|
|
rev: string;
|
|
};
|
|
|
|
export type ControlPlaneLogsRequest = {
|
|
packageName: string;
|
|
tail?: number;
|
|
stream?: "stdout" | "stderr" | "all";
|
|
};
|
|
|
|
export type ControlPlaneErrorsRequest = {
|
|
packageName?: string;
|
|
stateContextId?: string;
|
|
tail?: number;
|
|
acknowledge?: boolean;
|
|
};
|
|
|
|
export type ControlPlaneReplEvalRequest = {
|
|
sessionId?: string;
|
|
code: string;
|
|
autoClose?: boolean;
|
|
defaultStateContextId?: string | null;
|
|
};
|
|
|
|
export type ControlPlaneReplCloseRequest = {
|
|
sessionId: string;
|
|
};
|
|
|
|
export type ControlPlaneDeviceTarget = {
|
|
packageName: string;
|
|
stateContextId: string;
|
|
surfaceId: string;
|
|
requestFullscreen?: boolean;
|
|
};
|
|
|
|
export type ControlPlaneDeviceViewport = {
|
|
width: number;
|
|
height: number;
|
|
pixelRatio: number | null;
|
|
};
|
|
|
|
export type ControlPlaneDevice = {
|
|
deviceId: string;
|
|
name: string | null;
|
|
createdAt: string;
|
|
lastSeenAt: string | null;
|
|
connected: boolean;
|
|
assignment: ControlPlaneDeviceTarget | null;
|
|
configuredAssignment: ControlPlaneDeviceTarget | null;
|
|
identifyUntil: string | null;
|
|
lastUserAgent: string | null;
|
|
viewport: ControlPlaneDeviceViewport | null;
|
|
};
|
|
|
|
export type ControlPlaneDevicesResponse = {
|
|
devices: ControlPlaneDevice[];
|
|
};
|
|
|
|
export type ControlPlaneDeviceAssignRequest = {
|
|
deviceId: string;
|
|
target: ControlPlaneDeviceTarget | null;
|
|
};
|
|
|
|
export type ControlPlaneDeviceRenameRequest = {
|
|
deviceId: string;
|
|
name: string | null;
|
|
};
|
|
|
|
export type ControlPlaneDeviceRemoveRequest = {
|
|
deviceId: string;
|
|
};
|
|
|
|
export type ControlPlaneDeviceIdentifyRequest = {
|
|
deviceId: string;
|
|
durationMs?: number;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSessionRequest = {
|
|
deviceId: string;
|
|
requestedTarget?: ControlPlaneDeviceTarget | null;
|
|
userAgent?: string | null;
|
|
viewport?: ControlPlaneDeviceViewport | null;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSessionResponse = {
|
|
device: ControlPlaneDevice;
|
|
};
|
|
|
|
export type ControlPlaneWorkspacePackage = {
|
|
packageName: string;
|
|
headCommit: string;
|
|
ignored: boolean;
|
|
};
|
|
|
|
export type ControlPlaneStateContext = {
|
|
id: string;
|
|
packageName: string;
|
|
packageRef: string;
|
|
createdAt: string;
|
|
parentStateContextId: string | null;
|
|
namespace: string | null;
|
|
kind: "root" | "derived";
|
|
};
|
|
|
|
export type ControlPlaneBrowserAuthMessage = {
|
|
type: "auth";
|
|
secret: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserOpenRootContextParams = {
|
|
target: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserOpenDerivedContextParams = {
|
|
target: string;
|
|
targetPackageName?: string;
|
|
callerStateContextId: string;
|
|
contextNamespace?: string | null;
|
|
};
|
|
|
|
export type ControlPlaneBrowserCloseStateContextParams = {
|
|
stateContextId: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserCallParams = {
|
|
target: string;
|
|
functionName: string;
|
|
params: unknown;
|
|
stateContextId: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserValueGetParams = {
|
|
target: string;
|
|
valueName: string;
|
|
params: unknown;
|
|
stateContextId: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserSubscribeParams = {
|
|
target: string;
|
|
resourceName: string;
|
|
params: unknown;
|
|
stateContextId: string;
|
|
subscriptionNamespace?: string | null;
|
|
};
|
|
|
|
export type ControlPlaneBrowserUnsubscribeParams = {
|
|
subscriptionId: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserSubscriptionReadyParams = {
|
|
subscriptionId: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserRequestMessage =
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "open-root-context";
|
|
params: ControlPlaneBrowserOpenRootContextParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "open-derived-context";
|
|
params: ControlPlaneBrowserOpenDerivedContextParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "close-state-context";
|
|
params: ControlPlaneBrowserCloseStateContextParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "call";
|
|
params: ControlPlaneBrowserCallParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "value-get";
|
|
params: ControlPlaneBrowserValueGetParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "event-subscribe";
|
|
params: ControlPlaneBrowserSubscribeParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "value-watch";
|
|
params: ControlPlaneBrowserSubscribeParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "unsubscribe";
|
|
params: ControlPlaneBrowserUnsubscribeParams;
|
|
}
|
|
| {
|
|
type: "request";
|
|
requestId: string;
|
|
method: "subscription-ready";
|
|
params: ControlPlaneBrowserSubscriptionReadyParams;
|
|
};
|
|
|
|
export type ControlPlaneBrowserClientMessage =
|
|
| ControlPlaneBrowserAuthMessage
|
|
| ControlPlaneBrowserRequestMessage;
|
|
|
|
export type ControlPlaneBrowserResponseMessage = {
|
|
type: "response";
|
|
requestId: string;
|
|
ok: boolean;
|
|
result?: unknown;
|
|
error?: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserSubscriptionDataMessage = {
|
|
type: "subscription-data";
|
|
subscriptionId: string;
|
|
data: unknown;
|
|
};
|
|
|
|
export type ControlPlaneBrowserAuthAckMessage = {
|
|
type: "auth-ack";
|
|
};
|
|
|
|
export type ControlPlaneBrowserStatusInvalidatedMessage = {
|
|
type: "status-invalidated";
|
|
reason:
|
|
| "state-context-opened"
|
|
| "state-context-closed"
|
|
| "running-packages-changed"
|
|
| "repl-sessions-changed"
|
|
| "runtime-errors-changed"
|
|
| "devices-changed";
|
|
};
|
|
|
|
export type ControlPlaneDeviceSocketConnectMessage = {
|
|
type: "device-connect";
|
|
deviceId: string;
|
|
requestedTarget?: ControlPlaneDeviceTarget | null;
|
|
userAgent?: string | null;
|
|
viewport?: ControlPlaneDeviceViewport | null;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSocketUpdateMessage = {
|
|
type: "device-update";
|
|
viewport?: ControlPlaneDeviceViewport | null;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSocketClientMessage =
|
|
| ControlPlaneDeviceSocketConnectMessage
|
|
| ControlPlaneDeviceSocketUpdateMessage;
|
|
|
|
export type ControlPlaneDeviceSocketReadyMessage = {
|
|
type: "device-ready";
|
|
device: ControlPlaneDevice;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSocketStateMessage = {
|
|
type: "device-state";
|
|
device: ControlPlaneDevice;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSocketRemovedMessage = {
|
|
type: "device-removed";
|
|
deviceId: string;
|
|
};
|
|
|
|
export type ControlPlaneDeviceSocketServerMessage =
|
|
| ControlPlaneDeviceSocketReadyMessage
|
|
| ControlPlaneDeviceSocketStateMessage
|
|
| ControlPlaneDeviceSocketRemovedMessage;
|
|
|
|
export type ControlPlanePackageLogEntry = {
|
|
id: string;
|
|
createdAt: string;
|
|
packageName: string;
|
|
label: string;
|
|
processId: number | null;
|
|
stream: "stdout" | "stderr";
|
|
text: string;
|
|
};
|
|
|
|
export type ControlPlaneRuntimeErrorPhase =
|
|
| "on-create"
|
|
| "on-destroy"
|
|
| "on-context-open"
|
|
| "on-context-close"
|
|
| "browser-surface"
|
|
| "function"
|
|
| "event-subscribe"
|
|
| "event-cleanup"
|
|
| "value-get"
|
|
| "value-watch"
|
|
| "value-cleanup"
|
|
| "subscription-publish"
|
|
| "internal";
|
|
|
|
export type ControlPlanePackageErrorEntry = {
|
|
id: string;
|
|
createdAt: string;
|
|
packageName: string;
|
|
label: string | null;
|
|
processId: number | null;
|
|
stateContextId: string | null;
|
|
phase: ControlPlaneRuntimeErrorPhase;
|
|
functionName: string | null;
|
|
resourceKind: "event" | "value" | null;
|
|
resourceName: string | null;
|
|
surfaceId: string | null;
|
|
hostSessionId: string | null;
|
|
message: string;
|
|
stack: string | null;
|
|
acknowledgedAt: string | null;
|
|
};
|
|
|
|
export type ControlPlaneLogsResponse = {
|
|
packageName: string;
|
|
entries: ControlPlanePackageLogEntry[];
|
|
};
|
|
|
|
export type ControlPlaneErrorsResponse = {
|
|
entries: ControlPlanePackageErrorEntry[];
|
|
acknowledgedCount: number;
|
|
};
|
|
|
|
export type ControlPlaneReplSession = {
|
|
sessionId: string;
|
|
createdAt: string;
|
|
lastActivityAt: string;
|
|
ownedStateContextIds: string[];
|
|
borrowedStateContextIds: string[];
|
|
subscriptionCount: number;
|
|
tempDirectory: string;
|
|
};
|
|
|
|
export type ControlPlaneBrowserServerMessage =
|
|
| ControlPlaneBrowserAuthAckMessage
|
|
| ControlPlaneBrowserStatusInvalidatedMessage
|
|
| ControlPlaneBrowserResponseMessage
|
|
| ControlPlaneBrowserSubscriptionDataMessage;
|
|
|
|
export type ControlPlaneDependencyInput = {
|
|
inputName: string;
|
|
targetNodeId: string;
|
|
};
|
|
|
|
export type ControlPlaneDependencyNode = {
|
|
nodeId: string;
|
|
label: string;
|
|
originalRef: string | null;
|
|
lockedRef: string | null;
|
|
version: string | null;
|
|
inputs: ControlPlaneDependencyInput[];
|
|
};
|
|
|
|
export type ControlPlaneDependencyGraph = {
|
|
rootNodeId: string;
|
|
nodes: ControlPlaneDependencyNode[];
|
|
};
|
|
|
|
export type ControlPlaneRunningPackage = {
|
|
key: string;
|
|
label: string;
|
|
packageName: string;
|
|
flakeRef: string;
|
|
requestedRef: string | null;
|
|
connected: boolean;
|
|
processId: number | null;
|
|
openedStateContextIds: string[];
|
|
rootStateContextIds: string[];
|
|
resolvedRef: string | null;
|
|
version: string | null;
|
|
unreadErrorCount: number;
|
|
lastErrorAt: string | null;
|
|
dependencyGraph: ControlPlaneDependencyGraph | null;
|
|
dependencyGraphError: string | null;
|
|
};
|
|
|
|
export type ControlPlaneCheckStatus = "running" | "passed" | "failed";
|
|
|
|
export type ControlPlaneCheckResult = {
|
|
packageName: string;
|
|
rev: string;
|
|
status: ControlPlaneCheckStatus;
|
|
startedAt: string;
|
|
finishedAt: string | null;
|
|
summary: string | null;
|
|
logExcerpt: string | null;
|
|
};
|
|
|
|
export type ControlPlaneSchemaResourceDescription = {
|
|
name: string;
|
|
description: string | null;
|
|
annotations: Array<Record<string, unknown> & { type: string }>;
|
|
takesParams: boolean;
|
|
inputDescription: string | null;
|
|
inputJsonSchema: Record<string, unknown> | null;
|
|
outputDescription: string | null;
|
|
outputJsonSchema: Record<string, unknown> | null;
|
|
paramsDescription: string | null;
|
|
paramsJsonSchema: Record<string, unknown> | null;
|
|
dataDescription: string | null;
|
|
dataJsonSchema: Record<string, unknown> | null;
|
|
history?: boolean;
|
|
payloadMode: string | null;
|
|
};
|
|
|
|
export type ControlPlanePackageSchemaDescription = {
|
|
packageName: string;
|
|
schemaPackageName: string;
|
|
description: string | null;
|
|
annotations: Array<Record<string, unknown> & { type: string }>;
|
|
functions: ControlPlaneSchemaResourceDescription[];
|
|
events: ControlPlaneSchemaResourceDescription[];
|
|
values: ControlPlaneSchemaResourceDescription[];
|
|
};
|
|
|
|
export type ControlPlaneSchemaDescriptionResult = {
|
|
packageName: string;
|
|
rev: string;
|
|
generatedAt: string;
|
|
status: "available" | "unavailable";
|
|
data: ControlPlanePackageSchemaDescription | null;
|
|
error: string | null;
|
|
};
|
|
|
|
export type ControlPlaneRunResponse = {
|
|
stateContextId: string;
|
|
package: ControlPlaneRunningPackage;
|
|
};
|
|
|
|
export type ControlPlaneClearStateResponse = {
|
|
packageNames: string[];
|
|
clearedDirectories: string[];
|
|
packages: ControlPlaneRunningPackage[];
|
|
};
|
|
|
|
export type ControlPlaneReplLogEntry = {
|
|
level: "log" | "info" | "warn" | "error";
|
|
text: string;
|
|
};
|
|
|
|
export type ControlPlaneReplEvalResponse = {
|
|
session: ControlPlaneReplSession;
|
|
created: boolean;
|
|
closed: boolean;
|
|
ok: boolean;
|
|
result: string | null;
|
|
logs: ControlPlaneReplLogEntry[];
|
|
error: string | null;
|
|
};
|
|
|
|
export type ControlPlaneReplCloseResponse = {
|
|
sessionId: string;
|
|
closed: boolean;
|
|
};
|
|
|
|
export type ControlPlaneRemoteDomPayload = {
|
|
protocol: string;
|
|
revision: number;
|
|
baseRevision: number | null;
|
|
fromEmpty: boolean;
|
|
mutations: unknown[];
|
|
};
|
|
|
|
export type ControlPlaneStatusResponse = {
|
|
generatedAt: string;
|
|
workspacePackages: ControlPlaneWorkspacePackage[];
|
|
stateContexts: ControlPlaneStateContext[];
|
|
replSessions: ControlPlaneReplSession[];
|
|
devices: ControlPlaneDevice[];
|
|
packages: ControlPlaneRunningPackage[];
|
|
checks: ControlPlaneCheckResult[];
|
|
descriptions: ControlPlaneSchemaDescriptionResult[];
|
|
};
|
|
|
|
export type ControlPlaneCutoverResponse = {
|
|
packages: ControlPlaneRunningPackage[];
|
|
};
|
|
|
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
typeof value === "object" && value !== null;
|
|
|
|
const isString = (value: unknown): value is string => typeof value === "string";
|
|
|
|
const isNullableString = (value: unknown): value is string | null =>
|
|
value === null || typeof value === "string";
|
|
|
|
const isNullableRecord = (
|
|
value: unknown,
|
|
): value is Record<string, unknown> | null =>
|
|
value === null || isRecord(value);
|
|
|
|
const isPositiveInteger = (value: unknown): value is number =>
|
|
typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
|
|
const isRuntimeErrorPhase = (
|
|
value: unknown,
|
|
): value is ControlPlaneRuntimeErrorPhase =>
|
|
value === "on-create" ||
|
|
value === "on-destroy" ||
|
|
value === "on-context-open" ||
|
|
value === "on-context-close" ||
|
|
value === "browser-surface" ||
|
|
value === "function" ||
|
|
value === "event-subscribe" ||
|
|
value === "event-cleanup" ||
|
|
value === "value-get" ||
|
|
value === "value-watch" ||
|
|
value === "value-cleanup" ||
|
|
value === "subscription-publish" ||
|
|
value === "internal";
|
|
|
|
const isSchemaAnnotation = (
|
|
value: unknown,
|
|
): value is Record<string, unknown> & { type: string } =>
|
|
isRecord(value) && isString(value.type);
|
|
|
|
const isSchemaAnnotationArray = (
|
|
value: unknown,
|
|
): value is Array<Record<string, unknown> & { type: string }> =>
|
|
Array.isArray(value) && value.every((item) => isSchemaAnnotation(item));
|
|
|
|
const isStringArray = (value: unknown): value is string[] =>
|
|
Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
|
|
const isCheckStatus = (value: unknown): value is ControlPlaneCheckStatus =>
|
|
value === "running" || value === "passed" || value === "failed";
|
|
|
|
const isPositiveNumber = (value: unknown): value is number =>
|
|
typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
|
|
const parseControlPlaneDeviceViewport = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceViewport | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isPositiveNumber(value.width) ||
|
|
!isPositiveNumber(value.height) ||
|
|
!(
|
|
value.pixelRatio === undefined ||
|
|
value.pixelRatio === null ||
|
|
isPositiveNumber(value.pixelRatio)
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
width: value.width,
|
|
height: value.height,
|
|
pixelRatio: value.pixelRatio ?? null,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceTarget = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceTarget | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isNonEmptyString(value.packageName) ||
|
|
!isNonEmptyString(value.stateContextId) ||
|
|
!isNonEmptyString(value.surfaceId) ||
|
|
!(
|
|
value.requestFullscreen === undefined ||
|
|
typeof value.requestFullscreen === "boolean"
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
stateContextId: value.stateContextId,
|
|
surfaceId: value.surfaceId,
|
|
requestFullscreen: value.requestFullscreen,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDevice = (
|
|
value: unknown,
|
|
): ControlPlaneDevice | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isNonEmptyString(value.deviceId) ||
|
|
!isNullableString(value.name) ||
|
|
!isString(value.createdAt) ||
|
|
!isNullableString(value.lastSeenAt) ||
|
|
typeof value.connected !== "boolean" ||
|
|
!isNullableString(value.identifyUntil) ||
|
|
!isNullableString(value.lastUserAgent)
|
|
) {
|
|
return null;
|
|
}
|
|
const assignment =
|
|
value.assignment === undefined || value.assignment === null
|
|
? null
|
|
: parseControlPlaneDeviceTarget(value.assignment);
|
|
if (value.assignment !== undefined && value.assignment !== null && !assignment) {
|
|
return null;
|
|
}
|
|
const configuredAssignment =
|
|
value.configuredAssignment === undefined || value.configuredAssignment === null
|
|
? null
|
|
: parseControlPlaneDeviceTarget(value.configuredAssignment);
|
|
if (
|
|
value.configuredAssignment !== undefined &&
|
|
value.configuredAssignment !== null &&
|
|
!configuredAssignment
|
|
) {
|
|
return null;
|
|
}
|
|
const viewport =
|
|
value.viewport === undefined || value.viewport === null
|
|
? null
|
|
: parseControlPlaneDeviceViewport(value.viewport);
|
|
if (value.viewport !== undefined && value.viewport !== null && !viewport) {
|
|
return null;
|
|
}
|
|
return {
|
|
deviceId: value.deviceId,
|
|
name: value.name,
|
|
createdAt: value.createdAt,
|
|
lastSeenAt: value.lastSeenAt,
|
|
connected: value.connected,
|
|
assignment,
|
|
configuredAssignment,
|
|
identifyUntil: value.identifyUntil,
|
|
lastUserAgent: value.lastUserAgent,
|
|
viewport,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneRunRequest = (
|
|
value: unknown,
|
|
): ControlPlaneRunRequest | null => {
|
|
if (!isRecord(value) || !isString(value.target) || value.target.length === 0) {
|
|
return null;
|
|
}
|
|
return {
|
|
target: value.target,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneCheckRequest = (
|
|
value: unknown,
|
|
): ControlPlaneCheckRequest | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.packageName) ||
|
|
value.packageName.length === 0 ||
|
|
!isString(value.rev) ||
|
|
value.rev.length === 0
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
rev: value.rev,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneCutoverRequest = (
|
|
value: unknown,
|
|
): ControlPlaneCutoverRequest | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!Array.isArray(value.targets) ||
|
|
!value.targets.every(
|
|
(target) => typeof target === "string" && target.length > 0,
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
targets: value.targets,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneClearStateRequest = (
|
|
value: unknown,
|
|
): ControlPlaneClearStateRequest | null => {
|
|
if (!isRecord(value) || !isString(value.packageName)) {
|
|
return null;
|
|
}
|
|
if (
|
|
value.recursive !== undefined &&
|
|
typeof value.recursive !== "boolean"
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
recursive: value.recursive,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDescribeRequest = (
|
|
value: unknown,
|
|
): ControlPlaneDescribeRequest | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.packageName) ||
|
|
value.packageName.length === 0 ||
|
|
!isString(value.rev) ||
|
|
value.rev.length === 0
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
rev: value.rev,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneLogsRequest = (
|
|
value: unknown,
|
|
): ControlPlaneLogsRequest | null => {
|
|
if (!isRecord(value) || !isString(value.packageName)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!(
|
|
value.tail === undefined ||
|
|
value.tail === null ||
|
|
isPositiveInteger(value.tail)
|
|
) ||
|
|
!(
|
|
value.stream === undefined ||
|
|
value.stream === "stdout" ||
|
|
value.stream === "stderr" ||
|
|
value.stream === "all"
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
tail: value.tail ?? undefined,
|
|
stream: value.stream ?? undefined,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneErrorsRequest = (
|
|
value: unknown,
|
|
): ControlPlaneErrorsRequest | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!(
|
|
value.packageName === undefined ||
|
|
value.packageName === null ||
|
|
isString(value.packageName)
|
|
) ||
|
|
!(
|
|
value.stateContextId === undefined ||
|
|
value.stateContextId === null ||
|
|
isString(value.stateContextId)
|
|
) ||
|
|
!(
|
|
value.tail === undefined ||
|
|
value.tail === null ||
|
|
isPositiveInteger(value.tail)
|
|
) ||
|
|
!(
|
|
value.acknowledge === undefined ||
|
|
typeof value.acknowledge === "boolean"
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName ?? undefined,
|
|
stateContextId: value.stateContextId ?? undefined,
|
|
tail: value.tail ?? undefined,
|
|
acknowledge: value.acknowledge ?? undefined,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceAssignRequest = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceAssignRequest | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.deviceId)) {
|
|
return null;
|
|
}
|
|
const target =
|
|
value.target === undefined || value.target === null
|
|
? null
|
|
: parseControlPlaneDeviceTarget(value.target);
|
|
if (value.target !== undefined && value.target !== null && !target) {
|
|
return null;
|
|
}
|
|
return {
|
|
deviceId: value.deviceId,
|
|
target,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceRenameRequest = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceRenameRequest | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isNonEmptyString(value.deviceId) ||
|
|
!(
|
|
value.name === undefined ||
|
|
value.name === null ||
|
|
typeof value.name === "string"
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
deviceId: value.deviceId,
|
|
name: value.name ?? null,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceRemoveRequest = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceRemoveRequest | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.deviceId)) {
|
|
return null;
|
|
}
|
|
return {
|
|
deviceId: value.deviceId,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceIdentifyRequest = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceIdentifyRequest | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isNonEmptyString(value.deviceId) ||
|
|
!(
|
|
value.durationMs === undefined ||
|
|
(typeof value.durationMs === "number" &&
|
|
Number.isInteger(value.durationMs) &&
|
|
value.durationMs > 0)
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
deviceId: value.deviceId,
|
|
durationMs: value.durationMs,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceSessionRequest = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceSessionRequest | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isNonEmptyString(value.deviceId) ||
|
|
!(
|
|
value.userAgent === undefined ||
|
|
value.userAgent === null ||
|
|
typeof value.userAgent === "string"
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
const requestedTarget =
|
|
value.requestedTarget === undefined
|
|
? undefined
|
|
: value.requestedTarget === null
|
|
? null
|
|
: parseControlPlaneDeviceTarget(value.requestedTarget);
|
|
if (
|
|
value.requestedTarget !== undefined &&
|
|
value.requestedTarget !== null &&
|
|
!requestedTarget
|
|
) {
|
|
return null;
|
|
}
|
|
const viewport =
|
|
value.viewport === undefined || value.viewport === null
|
|
? null
|
|
: parseControlPlaneDeviceViewport(value.viewport);
|
|
if (value.viewport !== undefined && value.viewport !== null && !viewport) {
|
|
return null;
|
|
}
|
|
return {
|
|
deviceId: value.deviceId,
|
|
...(requestedTarget !== undefined ? { requestedTarget } : {}),
|
|
userAgent: value.userAgent ?? null,
|
|
viewport,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneReplEvalRequest = (
|
|
value: unknown,
|
|
): ControlPlaneReplEvalRequest | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.code)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!(
|
|
value.sessionId === undefined ||
|
|
isNonEmptyString(value.sessionId)
|
|
) ||
|
|
!(
|
|
value.autoClose === undefined ||
|
|
typeof value.autoClose === "boolean"
|
|
) ||
|
|
!(
|
|
value.defaultStateContextId === undefined ||
|
|
value.defaultStateContextId === null ||
|
|
isNonEmptyString(value.defaultStateContextId)
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
sessionId: value.sessionId,
|
|
code: value.code,
|
|
autoClose: value.autoClose,
|
|
defaultStateContextId: value.defaultStateContextId ?? null,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneReplCloseRequest = (
|
|
value: unknown,
|
|
): ControlPlaneReplCloseRequest | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.sessionId)) {
|
|
return null;
|
|
}
|
|
return {
|
|
sessionId: value.sessionId,
|
|
};
|
|
};
|
|
|
|
const isNonEmptyString = (value: unknown): value is string =>
|
|
typeof value === "string" && value.length > 0;
|
|
|
|
const parseBrowserSubscribeParams = (
|
|
value: unknown,
|
|
): ControlPlaneBrowserSubscribeParams | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isNonEmptyString(value.target) ||
|
|
!isNonEmptyString(value.resourceName) ||
|
|
!isNonEmptyString(value.stateContextId) ||
|
|
!(
|
|
value.subscriptionNamespace === undefined ||
|
|
value.subscriptionNamespace === null ||
|
|
typeof value.subscriptionNamespace === "string"
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
target: value.target,
|
|
resourceName: value.resourceName,
|
|
params: value.params,
|
|
stateContextId: value.stateContextId,
|
|
subscriptionNamespace: value.subscriptionNamespace ?? null,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDeviceSocketClientMessage = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceSocketClientMessage | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.type)) {
|
|
return null;
|
|
}
|
|
if (value.type === "device-connect") {
|
|
const parsed = parseControlPlaneDeviceSessionRequest(value);
|
|
if (!parsed) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "device-connect",
|
|
deviceId: parsed.deviceId,
|
|
...(parsed.requestedTarget !== undefined
|
|
? { requestedTarget: parsed.requestedTarget }
|
|
: {}),
|
|
...(parsed.userAgent !== undefined ? { userAgent: parsed.userAgent } : {}),
|
|
...(parsed.viewport !== undefined ? { viewport: parsed.viewport } : {}),
|
|
};
|
|
}
|
|
if (value.type === "device-update") {
|
|
const viewport =
|
|
value.viewport === undefined || value.viewport === null
|
|
? value.viewport
|
|
: parseControlPlaneDeviceViewport(value.viewport);
|
|
if (value.viewport !== undefined && value.viewport !== null && !viewport) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "device-update",
|
|
...(value.viewport !== undefined ? { viewport: viewport ?? null } : {}),
|
|
};
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const parseControlPlaneDeviceSocketServerMessage = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceSocketServerMessage | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.type)) {
|
|
return null;
|
|
}
|
|
if (value.type === "device-removed") {
|
|
if (!isNonEmptyString(value.deviceId)) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "device-removed",
|
|
deviceId: value.deviceId,
|
|
};
|
|
}
|
|
if (value.type !== "device-ready" && value.type !== "device-state") {
|
|
return null;
|
|
}
|
|
const device = parseControlPlaneDevice(value.device);
|
|
if (!device) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: value.type,
|
|
device,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneBrowserClientMessage = (
|
|
value: unknown,
|
|
): ControlPlaneBrowserClientMessage | null => {
|
|
if (!isRecord(value) || !isNonEmptyString(value.type)) {
|
|
return null;
|
|
}
|
|
|
|
if (value.type === "auth") {
|
|
if (!isNonEmptyString(value.secret)) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "auth",
|
|
secret: value.secret,
|
|
};
|
|
}
|
|
|
|
if (value.type !== "request") {
|
|
return null;
|
|
}
|
|
if (!isNonEmptyString(value.requestId) || !isNonEmptyString(value.method)) {
|
|
return null;
|
|
}
|
|
|
|
switch (value.method) {
|
|
case "open-root-context":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.target)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "open-root-context",
|
|
params: {
|
|
target: value.params.target,
|
|
},
|
|
};
|
|
case "open-derived-context":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.target) ||
|
|
!isNonEmptyString(value.params.callerStateContextId) ||
|
|
!(
|
|
value.params.targetPackageName === undefined ||
|
|
isNonEmptyString(value.params.targetPackageName)
|
|
) ||
|
|
!(
|
|
value.params.contextNamespace === undefined ||
|
|
value.params.contextNamespace === null ||
|
|
isNonEmptyString(value.params.contextNamespace)
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "open-derived-context",
|
|
params: {
|
|
target: value.params.target,
|
|
targetPackageName: value.params.targetPackageName,
|
|
callerStateContextId: value.params.callerStateContextId,
|
|
contextNamespace: value.params.contextNamespace ?? null,
|
|
},
|
|
};
|
|
case "close-state-context":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.stateContextId)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "close-state-context",
|
|
params: {
|
|
stateContextId: value.params.stateContextId,
|
|
},
|
|
};
|
|
case "call":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.target) ||
|
|
!isNonEmptyString(value.params.functionName) ||
|
|
!isNonEmptyString(value.params.stateContextId)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "call",
|
|
params: {
|
|
target: value.params.target,
|
|
functionName: value.params.functionName,
|
|
params: value.params.params,
|
|
stateContextId: value.params.stateContextId,
|
|
},
|
|
};
|
|
case "value-get":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.target) ||
|
|
!isNonEmptyString(value.params.valueName) ||
|
|
!isNonEmptyString(value.params.stateContextId)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "value-get",
|
|
params: {
|
|
target: value.params.target,
|
|
valueName: value.params.valueName,
|
|
params: value.params.params,
|
|
stateContextId: value.params.stateContextId,
|
|
},
|
|
};
|
|
case "event-subscribe": {
|
|
const params = parseBrowserSubscribeParams(value.params);
|
|
if (!params) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "event-subscribe",
|
|
params,
|
|
};
|
|
}
|
|
case "value-watch": {
|
|
const params = parseBrowserSubscribeParams(value.params);
|
|
if (!params) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "value-watch",
|
|
params,
|
|
};
|
|
}
|
|
case "unsubscribe":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.subscriptionId)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "unsubscribe",
|
|
params: {
|
|
subscriptionId: value.params.subscriptionId,
|
|
},
|
|
};
|
|
case "subscription-ready":
|
|
if (
|
|
!isRecord(value.params) ||
|
|
!isNonEmptyString(value.params.subscriptionId)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
type: "request",
|
|
requestId: value.requestId,
|
|
method: "subscription-ready",
|
|
params: {
|
|
subscriptionId: value.params.subscriptionId,
|
|
},
|
|
};
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const parseDependencyInput = (
|
|
value: unknown,
|
|
): ControlPlaneDependencyInput | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (!isString(value.inputName) || !isString(value.targetNodeId)) {
|
|
return null;
|
|
}
|
|
return {
|
|
inputName: value.inputName,
|
|
targetNodeId: value.targetNodeId,
|
|
};
|
|
};
|
|
|
|
const parseDependencyNode = (
|
|
value: unknown,
|
|
): ControlPlaneDependencyNode | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.nodeId) ||
|
|
!isString(value.label) ||
|
|
!isNullableString(value.originalRef) ||
|
|
!isNullableString(value.lockedRef) ||
|
|
!isNullableString(value.version) ||
|
|
!Array.isArray(value.inputs)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const inputs = value.inputs
|
|
.map((input) => parseDependencyInput(input))
|
|
.filter((input): input is ControlPlaneDependencyInput => input !== null);
|
|
if (inputs.length !== value.inputs.length) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
nodeId: value.nodeId,
|
|
label: value.label,
|
|
originalRef: value.originalRef,
|
|
lockedRef: value.lockedRef,
|
|
version: value.version,
|
|
inputs,
|
|
};
|
|
};
|
|
|
|
const parseControlPlaneWorkspacePackage = (
|
|
value: unknown,
|
|
): ControlPlaneWorkspacePackage | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.packageName) ||
|
|
!isString(value.headCommit) ||
|
|
typeof value.ignored !== "boolean"
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
headCommit: value.headCommit,
|
|
ignored: value.ignored,
|
|
};
|
|
};
|
|
|
|
const parseControlPlaneReplLogEntry = (
|
|
value: unknown,
|
|
): ControlPlaneReplLogEntry | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!(
|
|
value.level === "log" ||
|
|
value.level === "info" ||
|
|
value.level === "warn" ||
|
|
value.level === "error"
|
|
) ||
|
|
!isString(value.text)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
level: value.level,
|
|
text: value.text,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneReplSession = (
|
|
value: unknown,
|
|
): ControlPlaneReplSession | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.sessionId) ||
|
|
!isString(value.createdAt) ||
|
|
!isString(value.lastActivityAt) ||
|
|
!isStringArray(value.ownedStateContextIds) ||
|
|
!isStringArray(value.borrowedStateContextIds) ||
|
|
typeof value.subscriptionCount !== "number" ||
|
|
!isString(value.tempDirectory)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
sessionId: value.sessionId,
|
|
createdAt: value.createdAt,
|
|
lastActivityAt: value.lastActivityAt,
|
|
ownedStateContextIds: value.ownedStateContextIds,
|
|
borrowedStateContextIds: value.borrowedStateContextIds,
|
|
subscriptionCount: value.subscriptionCount,
|
|
tempDirectory: value.tempDirectory,
|
|
};
|
|
};
|
|
|
|
const parseDependencyGraph = (
|
|
value: unknown,
|
|
): ControlPlaneDependencyGraph | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (!isString(value.rootNodeId) || !Array.isArray(value.nodes)) {
|
|
return null;
|
|
}
|
|
const nodes = value.nodes
|
|
.map((node) => parseDependencyNode(node))
|
|
.filter((node): node is ControlPlaneDependencyNode => node !== null);
|
|
if (nodes.length !== value.nodes.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
rootNodeId: value.rootNodeId,
|
|
nodes,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneRunningPackage = (
|
|
value: unknown,
|
|
): ControlPlaneRunningPackage | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.key) ||
|
|
!isString(value.label) ||
|
|
!isString(value.packageName) ||
|
|
!isString(value.flakeRef) ||
|
|
!isNullableString(value.requestedRef) ||
|
|
typeof value.connected !== "boolean" ||
|
|
!(typeof value.processId === "number" || value.processId === null) ||
|
|
!isStringArray(value.openedStateContextIds) ||
|
|
!isStringArray(value.rootStateContextIds) ||
|
|
!isNullableString(value.resolvedRef) ||
|
|
!isNullableString(value.version) ||
|
|
!(
|
|
typeof value.unreadErrorCount === "number" &&
|
|
Number.isInteger(value.unreadErrorCount) &&
|
|
value.unreadErrorCount >= 0
|
|
) ||
|
|
!isNullableString(value.lastErrorAt) ||
|
|
!isNullableString(value.dependencyGraphError)
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
const dependencyGraph =
|
|
value.dependencyGraph === null
|
|
? null
|
|
: parseDependencyGraph(value.dependencyGraph);
|
|
if (value.dependencyGraph !== null && !dependencyGraph) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
key: value.key,
|
|
label: value.label,
|
|
packageName: value.packageName,
|
|
flakeRef: value.flakeRef,
|
|
requestedRef: value.requestedRef,
|
|
connected: value.connected,
|
|
processId: value.processId,
|
|
openedStateContextIds: value.openedStateContextIds,
|
|
rootStateContextIds: value.rootStateContextIds,
|
|
resolvedRef: value.resolvedRef,
|
|
version: value.version,
|
|
unreadErrorCount: value.unreadErrorCount,
|
|
lastErrorAt: value.lastErrorAt,
|
|
dependencyGraph,
|
|
dependencyGraphError: value.dependencyGraphError,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlanePackageLogEntry = (
|
|
value: unknown,
|
|
): ControlPlanePackageLogEntry | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.id) ||
|
|
!isString(value.createdAt) ||
|
|
!isString(value.packageName) ||
|
|
!isString(value.label) ||
|
|
!(typeof value.processId === "number" || value.processId === null) ||
|
|
!(value.stream === "stdout" || value.stream === "stderr") ||
|
|
!isString(value.text)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
id: value.id,
|
|
createdAt: value.createdAt,
|
|
packageName: value.packageName,
|
|
label: value.label,
|
|
processId: value.processId,
|
|
stream: value.stream,
|
|
text: value.text,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlanePackageErrorEntry = (
|
|
value: unknown,
|
|
): ControlPlanePackageErrorEntry | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.id) ||
|
|
!isString(value.createdAt) ||
|
|
!isString(value.packageName) ||
|
|
!isNullableString(value.label) ||
|
|
!(typeof value.processId === "number" || value.processId === null) ||
|
|
!isNullableString(value.stateContextId) ||
|
|
!isRuntimeErrorPhase(value.phase) ||
|
|
!isNullableString(value.functionName) ||
|
|
!(
|
|
value.resourceKind === "event" ||
|
|
value.resourceKind === "value" ||
|
|
value.resourceKind === null
|
|
) ||
|
|
!isNullableString(value.resourceName) ||
|
|
!(
|
|
value.surfaceId === undefined ||
|
|
isNullableString(value.surfaceId)
|
|
) ||
|
|
!(
|
|
value.hostSessionId === undefined ||
|
|
isNullableString(value.hostSessionId)
|
|
) ||
|
|
!isString(value.message) ||
|
|
!isNullableString(value.stack) ||
|
|
!isNullableString(value.acknowledgedAt)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
id: value.id,
|
|
createdAt: value.createdAt,
|
|
packageName: value.packageName,
|
|
label: value.label,
|
|
processId: value.processId,
|
|
stateContextId: value.stateContextId,
|
|
phase: value.phase,
|
|
functionName: value.functionName,
|
|
resourceKind: value.resourceKind,
|
|
resourceName: value.resourceName,
|
|
surfaceId: value.surfaceId ?? null,
|
|
hostSessionId: value.hostSessionId ?? null,
|
|
message: value.message,
|
|
stack: value.stack,
|
|
acknowledgedAt: value.acknowledgedAt,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneStateContext = (
|
|
value: unknown,
|
|
): ControlPlaneStateContext | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.id) ||
|
|
!isString(value.packageName) ||
|
|
!isString(value.packageRef) ||
|
|
!isString(value.createdAt) ||
|
|
!isNullableString(value.parentStateContextId) ||
|
|
!isNullableString(value.namespace) ||
|
|
!(value.kind === "root" || value.kind === "derived")
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
id: value.id,
|
|
packageName: value.packageName,
|
|
packageRef: value.packageRef,
|
|
createdAt: value.createdAt,
|
|
parentStateContextId: value.parentStateContextId,
|
|
namespace: value.namespace,
|
|
kind: value.kind,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneCheckResult = (
|
|
value: unknown,
|
|
): ControlPlaneCheckResult | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.packageName) ||
|
|
!isString(value.rev) ||
|
|
!isCheckStatus(value.status) ||
|
|
!isString(value.startedAt) ||
|
|
!isNullableString(value.finishedAt) ||
|
|
!isNullableString(value.summary) ||
|
|
!isNullableString(value.logExcerpt)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
rev: value.rev,
|
|
status: value.status,
|
|
startedAt: value.startedAt,
|
|
finishedAt: value.finishedAt,
|
|
summary: value.summary,
|
|
logExcerpt: value.logExcerpt,
|
|
};
|
|
};
|
|
|
|
const parseControlPlaneSchemaResourceDescription = (
|
|
value: unknown,
|
|
): ControlPlaneSchemaResourceDescription | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.name) ||
|
|
!isNullableString(value.description) ||
|
|
!(value.annotations === undefined || isSchemaAnnotationArray(value.annotations)) ||
|
|
typeof value.takesParams !== "boolean" ||
|
|
!isNullableString(value.inputDescription) ||
|
|
!(value.inputJsonSchema === undefined || isNullableRecord(value.inputJsonSchema)) ||
|
|
!isNullableString(value.outputDescription) ||
|
|
!(value.outputJsonSchema === undefined || isNullableRecord(value.outputJsonSchema)) ||
|
|
!isNullableString(value.paramsDescription) ||
|
|
!(value.paramsJsonSchema === undefined || isNullableRecord(value.paramsJsonSchema)) ||
|
|
!isNullableString(value.dataDescription) ||
|
|
!(value.dataJsonSchema === undefined || isNullableRecord(value.dataJsonSchema)) ||
|
|
!(typeof value.history === "boolean" || value.history === undefined) ||
|
|
!isNullableString(value.payloadMode)
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
name: value.name,
|
|
description: value.description,
|
|
annotations: value.annotations ?? [],
|
|
takesParams: value.takesParams,
|
|
inputDescription: value.inputDescription,
|
|
inputJsonSchema: value.inputJsonSchema ?? null,
|
|
outputDescription: value.outputDescription,
|
|
outputJsonSchema: value.outputJsonSchema ?? null,
|
|
paramsDescription: value.paramsDescription,
|
|
paramsJsonSchema: value.paramsJsonSchema ?? null,
|
|
dataDescription: value.dataDescription,
|
|
dataJsonSchema: value.dataJsonSchema ?? null,
|
|
history: value.history,
|
|
payloadMode: value.payloadMode,
|
|
};
|
|
};
|
|
|
|
const parseControlPlanePackageSchemaDescription = (
|
|
value: unknown,
|
|
): ControlPlanePackageSchemaDescription | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.packageName) ||
|
|
!isString(value.schemaPackageName) ||
|
|
!isNullableString(value.description) ||
|
|
!(value.annotations === undefined || isSchemaAnnotationArray(value.annotations)) ||
|
|
!Array.isArray(value.functions) ||
|
|
!Array.isArray(value.events) ||
|
|
!Array.isArray(value.values)
|
|
) {
|
|
return null;
|
|
}
|
|
const functions = value.functions
|
|
.map((entry) => parseControlPlaneSchemaResourceDescription(entry))
|
|
.filter(
|
|
(entry): entry is ControlPlaneSchemaResourceDescription => entry !== null,
|
|
);
|
|
const events = value.events
|
|
.map((entry) => parseControlPlaneSchemaResourceDescription(entry))
|
|
.filter(
|
|
(entry): entry is ControlPlaneSchemaResourceDescription => entry !== null,
|
|
);
|
|
const values = value.values
|
|
.map((entry) => parseControlPlaneSchemaResourceDescription(entry))
|
|
.filter(
|
|
(entry): entry is ControlPlaneSchemaResourceDescription => entry !== null,
|
|
);
|
|
if (
|
|
functions.length !== value.functions.length ||
|
|
events.length !== value.events.length ||
|
|
values.length !== value.values.length
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
schemaPackageName: value.schemaPackageName,
|
|
description: value.description,
|
|
annotations: value.annotations ?? [],
|
|
functions,
|
|
events,
|
|
values,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneSchemaDescriptionResult = (
|
|
value: unknown,
|
|
): ControlPlaneSchemaDescriptionResult | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
if (
|
|
!isString(value.packageName) ||
|
|
!isString(value.rev) ||
|
|
!isString(value.generatedAt) ||
|
|
!(value.status === "available" || value.status === "unavailable") ||
|
|
!isNullableString(value.error)
|
|
) {
|
|
return null;
|
|
}
|
|
const data =
|
|
value.data === null ? null : parseControlPlanePackageSchemaDescription(value.data);
|
|
if (value.data !== null && !data) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
rev: value.rev,
|
|
generatedAt: value.generatedAt,
|
|
status: value.status,
|
|
data,
|
|
error: value.error,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneRunResponse = (
|
|
value: unknown,
|
|
): ControlPlaneRunResponse | null => {
|
|
if (!isRecord(value) || !isString(value.stateContextId)) {
|
|
return null;
|
|
}
|
|
const parsedPackage = parseControlPlaneRunningPackage(value.package);
|
|
if (!parsedPackage) {
|
|
return null;
|
|
}
|
|
return {
|
|
stateContextId: value.stateContextId,
|
|
package: parsedPackage,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneStatusResponse = (
|
|
value: unknown,
|
|
): ControlPlaneStatusResponse | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.generatedAt) ||
|
|
!(
|
|
value.workspacePackages === undefined ||
|
|
Array.isArray(value.workspacePackages)
|
|
) ||
|
|
!(
|
|
value.stateContexts === undefined ||
|
|
Array.isArray(value.stateContexts)
|
|
) ||
|
|
!(
|
|
value.replSessions === undefined ||
|
|
Array.isArray(value.replSessions)
|
|
) ||
|
|
!(
|
|
value.devices === undefined ||
|
|
Array.isArray(value.devices)
|
|
) ||
|
|
!Array.isArray(value.packages) ||
|
|
!Array.isArray(value.checks) ||
|
|
!Array.isArray(value.descriptions)
|
|
) {
|
|
return null;
|
|
}
|
|
const workspacePackages = (value.workspacePackages ?? [])
|
|
.map((pkg) => parseControlPlaneWorkspacePackage(pkg))
|
|
.filter((pkg): pkg is ControlPlaneWorkspacePackage => pkg !== null);
|
|
if (workspacePackages.length !== (value.workspacePackages ?? []).length) {
|
|
return null;
|
|
}
|
|
const stateContexts = (value.stateContexts ?? [])
|
|
.map((context) => parseControlPlaneStateContext(context))
|
|
.filter((context): context is ControlPlaneStateContext => context !== null);
|
|
if (stateContexts.length !== (value.stateContexts ?? []).length) {
|
|
return null;
|
|
}
|
|
const replSessions = (value.replSessions ?? [])
|
|
.map((session) => parseControlPlaneReplSession(session))
|
|
.filter((session): session is ControlPlaneReplSession => session !== null);
|
|
if (replSessions.length !== (value.replSessions ?? []).length) {
|
|
return null;
|
|
}
|
|
const devices = (value.devices ?? [])
|
|
.map((device) => parseControlPlaneDevice(device))
|
|
.filter((device): device is ControlPlaneDevice => device !== null);
|
|
if (devices.length !== (value.devices ?? []).length) {
|
|
return null;
|
|
}
|
|
const packages = value.packages
|
|
.map((pkg) => parseControlPlaneRunningPackage(pkg))
|
|
.filter((pkg): pkg is ControlPlaneRunningPackage => pkg !== null);
|
|
if (packages.length !== value.packages.length) {
|
|
return null;
|
|
}
|
|
const checks = value.checks
|
|
.map((result) => parseControlPlaneCheckResult(result))
|
|
.filter((result): result is ControlPlaneCheckResult => result !== null);
|
|
if (checks.length !== value.checks.length) {
|
|
return null;
|
|
}
|
|
const descriptions = value.descriptions
|
|
.map((entry) => parseControlPlaneSchemaDescriptionResult(entry))
|
|
.filter(
|
|
(entry): entry is ControlPlaneSchemaDescriptionResult => entry !== null,
|
|
);
|
|
if (descriptions.length !== value.descriptions.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
generatedAt: value.generatedAt,
|
|
workspacePackages,
|
|
stateContexts,
|
|
replSessions,
|
|
devices,
|
|
packages,
|
|
checks,
|
|
descriptions,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneCutoverResponse = (
|
|
value: unknown,
|
|
): ControlPlaneCutoverResponse | null => {
|
|
if (!isRecord(value) || !Array.isArray(value.packages)) {
|
|
return null;
|
|
}
|
|
const packages = value.packages
|
|
.map((pkg) => parseControlPlaneRunningPackage(pkg))
|
|
.filter((pkg): pkg is ControlPlaneRunningPackage => pkg !== null);
|
|
if (packages.length !== value.packages.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
packages,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneDevicesResponse = (
|
|
value: unknown,
|
|
): ControlPlaneDevicesResponse | null => {
|
|
if (!isRecord(value) || !Array.isArray(value.devices)) {
|
|
return null;
|
|
}
|
|
const devices = value.devices
|
|
.map((device) => parseControlPlaneDevice(device))
|
|
.filter((device): device is ControlPlaneDevice => device !== null);
|
|
if (devices.length !== value.devices.length) {
|
|
return null;
|
|
}
|
|
return { devices };
|
|
};
|
|
|
|
export const parseControlPlaneDeviceSessionResponse = (
|
|
value: unknown,
|
|
): ControlPlaneDeviceSessionResponse | null => {
|
|
if (!isRecord(value)) {
|
|
return null;
|
|
}
|
|
const device = parseControlPlaneDevice(value.device);
|
|
if (!device) {
|
|
return null;
|
|
}
|
|
return { device };
|
|
};
|
|
|
|
export const parseControlPlaneReplEvalResponse = (
|
|
value: unknown,
|
|
): ControlPlaneReplEvalResponse | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
typeof value.created !== "boolean" ||
|
|
typeof value.closed !== "boolean" ||
|
|
typeof value.ok !== "boolean" ||
|
|
!isNullableString(value.result) ||
|
|
!Array.isArray(value.logs) ||
|
|
!isNullableString(value.error)
|
|
) {
|
|
return null;
|
|
}
|
|
const session = parseControlPlaneReplSession(value.session);
|
|
if (!session) {
|
|
return null;
|
|
}
|
|
const logs = value.logs
|
|
.map((entry) => parseControlPlaneReplLogEntry(entry))
|
|
.filter((entry): entry is ControlPlaneReplLogEntry => entry !== null);
|
|
if (logs.length !== value.logs.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
session,
|
|
created: value.created,
|
|
closed: value.closed,
|
|
ok: value.ok,
|
|
result: value.result,
|
|
logs,
|
|
error: value.error,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneReplCloseResponse = (
|
|
value: unknown,
|
|
): ControlPlaneReplCloseResponse | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isString(value.sessionId) ||
|
|
typeof value.closed !== "boolean"
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
sessionId: value.sessionId,
|
|
closed: value.closed,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneLogsResponse = (
|
|
value: unknown,
|
|
): ControlPlaneLogsResponse | null => {
|
|
if (!isRecord(value) || !isString(value.packageName) || !Array.isArray(value.entries)) {
|
|
return null;
|
|
}
|
|
const entries = value.entries
|
|
.map((entry) => parseControlPlanePackageLogEntry(entry))
|
|
.filter((entry): entry is ControlPlanePackageLogEntry => entry !== null);
|
|
if (entries.length !== value.entries.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageName: value.packageName,
|
|
entries,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneErrorsResponse = (
|
|
value: unknown,
|
|
): ControlPlaneErrorsResponse | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!Array.isArray(value.entries) ||
|
|
!(
|
|
typeof value.acknowledgedCount === "number" &&
|
|
Number.isInteger(value.acknowledgedCount) &&
|
|
value.acknowledgedCount >= 0
|
|
)
|
|
) {
|
|
return null;
|
|
}
|
|
const entries = value.entries
|
|
.map((entry) => parseControlPlanePackageErrorEntry(entry))
|
|
.filter((entry): entry is ControlPlanePackageErrorEntry => entry !== null);
|
|
if (entries.length !== value.entries.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
entries,
|
|
acknowledgedCount: value.acknowledgedCount,
|
|
};
|
|
};
|
|
|
|
export const parseControlPlaneClearStateResponse = (
|
|
value: unknown,
|
|
): ControlPlaneClearStateResponse | null => {
|
|
if (
|
|
!isRecord(value) ||
|
|
!isStringArray(value.packageNames) ||
|
|
!isStringArray(value.clearedDirectories) ||
|
|
!Array.isArray(value.packages)
|
|
) {
|
|
return null;
|
|
}
|
|
const packages = value.packages
|
|
.map((pkg) => parseControlPlaneRunningPackage(pkg))
|
|
.filter((pkg): pkg is ControlPlaneRunningPackage => pkg !== null);
|
|
if (packages.length !== value.packages.length) {
|
|
return null;
|
|
}
|
|
return {
|
|
packageNames: value.packageNames,
|
|
clearedDirectories: value.clearedDirectories,
|
|
packages,
|
|
};
|
|
};
|