feat: model presentation live replay status
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { presentationTargetHealth } from "./presentation-target-status.js";
|
||||
|
||||
describe("presentationTargetHealth", () => {
|
||||
it("shows replay evidence when no target exists", () => {
|
||||
expect(presentationTargetHealth({
|
||||
target: null,
|
||||
probe: "none",
|
||||
liveActive: false,
|
||||
})).toMatchObject({
|
||||
kind: "replay",
|
||||
label: "Replay evidence",
|
||||
});
|
||||
});
|
||||
|
||||
it("separates ready target from active live run", () => {
|
||||
expect(presentationTargetHealth({
|
||||
target: "http://127.0.0.1:8765/rpc",
|
||||
probe: "ready",
|
||||
liveActive: false,
|
||||
})).toMatchObject({
|
||||
kind: "ready",
|
||||
label: "Live target ready",
|
||||
});
|
||||
});
|
||||
|
||||
it("marks live active only after live timeline starts", () => {
|
||||
expect(presentationTargetHealth({
|
||||
target: "http://127.0.0.1:8765/rpc",
|
||||
probe: "ready",
|
||||
liveActive: true,
|
||||
})).toMatchObject({
|
||||
kind: "active",
|
||||
label: "Live run active",
|
||||
});
|
||||
});
|
||||
|
||||
it("shows replay fallback on failed health", () => {
|
||||
expect(presentationTargetHealth({
|
||||
target: "http://127.0.0.1:8765/rpc",
|
||||
probe: "failed",
|
||||
liveActive: false,
|
||||
failureReason: "connection refused",
|
||||
})).toMatchObject({
|
||||
kind: "failed",
|
||||
label: "Replay fallback",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
export type PresentationTargetHealth =
|
||||
| { readonly kind: "replay"; readonly label: string; readonly detail: string }
|
||||
| { readonly kind: "checking"; readonly target: string; readonly label: string; readonly detail: string }
|
||||
| { readonly kind: "ready"; readonly target: string; readonly label: string; readonly detail: string }
|
||||
| { readonly kind: "active"; readonly target: string; readonly label: string; readonly detail: string }
|
||||
| { readonly kind: "failed"; readonly target: string | null; readonly label: string; readonly detail: string };
|
||||
|
||||
export type TargetProbeState = "none" | "checking" | "ready" | "failed";
|
||||
|
||||
const shortTarget = (target: string): string => {
|
||||
const url = new URL(target);
|
||||
return `${url.hostname}:${url.port || (url.protocol === "https:" ? "443" : "80")}`;
|
||||
};
|
||||
|
||||
export const presentationTargetHealth = ({
|
||||
target,
|
||||
probe,
|
||||
liveActive,
|
||||
failureReason,
|
||||
}: {
|
||||
readonly target: string | null;
|
||||
readonly probe: TargetProbeState;
|
||||
readonly liveActive: boolean;
|
||||
readonly failureReason?: string | undefined;
|
||||
}): PresentationTargetHealth => {
|
||||
if (!target) {
|
||||
return {
|
||||
kind: "replay",
|
||||
label: "Replay evidence",
|
||||
detail: "reviewed recording",
|
||||
};
|
||||
}
|
||||
|
||||
if (liveActive && probe === "ready") {
|
||||
return {
|
||||
kind: "active",
|
||||
target,
|
||||
label: "Live run active",
|
||||
detail: `operations sent to ${shortTarget(target)}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (probe === "ready") {
|
||||
return {
|
||||
kind: "ready",
|
||||
target,
|
||||
label: "Live target ready",
|
||||
detail: shortTarget(target),
|
||||
};
|
||||
}
|
||||
|
||||
if (probe === "checking") {
|
||||
return {
|
||||
kind: "checking",
|
||||
target,
|
||||
label: "Live target configured",
|
||||
detail: "checking",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
kind: "failed",
|
||||
target,
|
||||
label: "Replay fallback",
|
||||
detail: failureReason ?? "live target unreachable",
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user