Archived
Merge remote-tracking branch 'origin/main' into investigate/issue-12-session-dir
# Conflicts: # src/client/src/api.ts # src/client/src/api/clients.ts # src/client/src/api/federatedRouteContract.test.ts # src/server/sessions/piSessionService.ts # src/server/sessions/sessionRoutes.ts
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
export type MachineKind = "local" | "remote";
|
||||
export type MachineStatus = "unknown" | "online" | "offline" | "error";
|
||||
|
||||
export const PI_WEB_CAPABILITIES = {
|
||||
sessionsDeleteArchived: "sessions.deleteArchived",
|
||||
} as const;
|
||||
|
||||
export type PiWebCapability = typeof PI_WEB_CAPABILITIES[keyof typeof PI_WEB_CAPABILITIES];
|
||||
|
||||
export interface Machine {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -22,6 +28,17 @@ export interface MachineHealth {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface MachineRuntime {
|
||||
machineId: string;
|
||||
ok: boolean;
|
||||
checkedAt: string;
|
||||
packageName?: string;
|
||||
generatedAt?: string;
|
||||
components?: PiWebRuntimeResponse["components"];
|
||||
capabilities?: PiWebCapability[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export type PiWebShortcutConfig = Record<string, string | null>;
|
||||
export type PiWebPluginSettings = Record<string, unknown>;
|
||||
export type PiWebPluginConfigMap = Record<string, PiWebPluginConfig>;
|
||||
@@ -47,6 +64,7 @@ export interface PiWebPluginInfo {
|
||||
module: string;
|
||||
source: string;
|
||||
scope: PiWebPluginScope;
|
||||
machineSpecific: boolean;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
@@ -340,6 +358,15 @@ export interface PiWebComponentStatus {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PiWebRuntimeComponent {
|
||||
component: PiWebServiceComponent;
|
||||
label: string;
|
||||
runtimeVersion?: string;
|
||||
available: boolean;
|
||||
capabilities: PiWebCapability[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PiWebReleaseStatus {
|
||||
packageName: string;
|
||||
latestVersion?: string;
|
||||
@@ -366,6 +393,16 @@ export interface PiWebVersionResponse {
|
||||
};
|
||||
}
|
||||
|
||||
export interface PiWebRuntimeResponse {
|
||||
packageName: string;
|
||||
generatedAt: string;
|
||||
components: {
|
||||
web: PiWebRuntimeComponent;
|
||||
sessiond: PiWebRuntimeComponent;
|
||||
};
|
||||
capabilities: PiWebCapability[];
|
||||
}
|
||||
|
||||
export interface PiWebStatusResponse extends PiWebVersionResponse {
|
||||
release: PiWebReleaseStatus;
|
||||
commands: {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { PI_WEB_CAPABILITIES, type PiWebCapability, type PiWebRuntimeComponent, type PiWebServiceComponent } from "./apiTypes.js";
|
||||
|
||||
export { PI_WEB_CAPABILITIES };
|
||||
export type { PiWebCapability };
|
||||
|
||||
export const KNOWN_PI_WEB_CAPABILITIES = Object.values(PI_WEB_CAPABILITIES);
|
||||
const knownPiWebCapabilities: ReadonlySet<string> = new Set(KNOWN_PI_WEB_CAPABILITIES);
|
||||
|
||||
export const WEB_RUNTIME_CAPABILITIES = [PI_WEB_CAPABILITIES.sessionsDeleteArchived] as const satisfies readonly PiWebCapability[];
|
||||
export const SESSIOND_RUNTIME_CAPABILITIES = [PI_WEB_CAPABILITIES.sessionsDeleteArchived] as const satisfies readonly PiWebCapability[];
|
||||
|
||||
const EFFECTIVE_CAPABILITY_REQUIREMENTS = {
|
||||
[PI_WEB_CAPABILITIES.sessionsDeleteArchived]: ["web", "sessiond"],
|
||||
} as const satisfies Record<PiWebCapability, readonly PiWebServiceComponent[]>;
|
||||
|
||||
export function isPiWebCapability(value: unknown): value is PiWebCapability {
|
||||
return typeof value === "string" && knownPiWebCapabilities.has(value);
|
||||
}
|
||||
|
||||
export function supportsPiWebCapability(source: { capabilities?: readonly PiWebCapability[] } | undefined, capability: PiWebCapability): boolean {
|
||||
return source?.capabilities?.includes(capability) === true;
|
||||
}
|
||||
|
||||
export function effectivePiWebCapabilities(components: Partial<Record<PiWebServiceComponent, Pick<PiWebRuntimeComponent, "available" | "capabilities">>>): PiWebCapability[] {
|
||||
return KNOWN_PI_WEB_CAPABILITIES.filter((capability) => {
|
||||
const requiredComponents = EFFECTIVE_CAPABILITY_REQUIREMENTS[capability];
|
||||
return requiredComponents.every((component) => {
|
||||
const runtime = components[component];
|
||||
return runtime?.available === true && supportsPiWebCapability(runtime, capability);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export interface FederatedHttpRouteSpec {
|
||||
}
|
||||
|
||||
export const FEDERATED_HTTP_ROUTES = [
|
||||
{ method: "GET", path: "/pi-web/status" },
|
||||
{ method: "GET", path: "/projects" },
|
||||
{ method: "POST", path: "/projects" },
|
||||
{ method: "DELETE", path: "/projects/:projectId" },
|
||||
@@ -48,6 +49,7 @@ export const FEDERATED_HTTP_ROUTES = [
|
||||
{ method: "POST", path: "/sessions/:sessionId/archive" },
|
||||
{ method: "POST", path: "/sessions/:sessionId/archive-tree" },
|
||||
{ method: "POST", path: "/sessions/:sessionId/restore" },
|
||||
{ method: "DELETE", path: "/sessions/:sessionId" },
|
||||
{ method: "POST", path: "/sessions/:sessionId/detach-parent" },
|
||||
{ method: "GET", path: "/auth/providers" },
|
||||
{ method: "POST", path: "/auth/api-key" },
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { PiWebComponentStatus, PiWebInstallationInfo, PiWebVersionResponse } from "./apiTypes.js";
|
||||
import type { PiWebCapability, PiWebComponentStatus, PiWebInstallationInfo, PiWebRuntimeComponent, PiWebRuntimeResponse, PiWebVersionResponse } from "./apiTypes.js";
|
||||
import { isPiWebCapability } from "./capabilities.js";
|
||||
|
||||
export function parsePiWebVersionResponse(value: unknown): PiWebVersionResponse | undefined {
|
||||
if (!isRecord(value)) return undefined;
|
||||
@@ -12,6 +13,39 @@ export function parsePiWebVersionResponse(value: unknown): PiWebVersionResponse
|
||||
return { packageName, generatedAt, components: { web, sessiond } };
|
||||
}
|
||||
|
||||
export function parsePiWebRuntimeResponse(value: unknown): PiWebRuntimeResponse | undefined {
|
||||
if (!isRecord(value)) return undefined;
|
||||
const packageName = value["packageName"];
|
||||
const generatedAt = value["generatedAt"];
|
||||
const components = value["components"];
|
||||
if (typeof packageName !== "string" || packageName === "" || typeof generatedAt !== "string" || generatedAt === "" || !isRecord(components)) return undefined;
|
||||
const web = parsePiWebRuntimeComponent(components["web"]);
|
||||
const sessiond = parsePiWebRuntimeComponent(components["sessiond"]);
|
||||
const capabilities = parsePiWebCapabilities(value["capabilities"]);
|
||||
if (web === undefined || sessiond === undefined || capabilities === undefined) return undefined;
|
||||
return { packageName, generatedAt, components: { web, sessiond }, capabilities };
|
||||
}
|
||||
|
||||
export function parsePiWebRuntimeComponent(value: unknown): PiWebRuntimeComponent | undefined {
|
||||
if (!isRecord(value)) return undefined;
|
||||
const component = value["component"];
|
||||
const label = value["label"];
|
||||
const runtimeVersion = value["runtimeVersion"];
|
||||
const available = value["available"];
|
||||
const capabilities = parsePiWebCapabilities(value["capabilities"]);
|
||||
const error = value["error"];
|
||||
if (component !== "web" && component !== "sessiond") return undefined;
|
||||
if (typeof label !== "string" || label === "" || typeof available !== "boolean" || capabilities === undefined) return undefined;
|
||||
return {
|
||||
component,
|
||||
label,
|
||||
...(typeof runtimeVersion === "string" ? { runtimeVersion } : {}),
|
||||
available,
|
||||
capabilities,
|
||||
...(typeof error === "string" ? { error } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export function parsePiWebComponentStatus(value: unknown): PiWebComponentStatus | undefined {
|
||||
if (!isRecord(value)) return undefined;
|
||||
const component = value["component"];
|
||||
@@ -36,6 +70,11 @@ export function parsePiWebComponentStatus(value: unknown): PiWebComponentStatus
|
||||
};
|
||||
}
|
||||
|
||||
function parsePiWebCapabilities(value: unknown): PiWebCapability[] | undefined {
|
||||
if (!Array.isArray(value) || !value.every(isPiWebCapability)) return undefined;
|
||||
return value;
|
||||
}
|
||||
|
||||
export function parsePiWebInstallationInfo(value: unknown): PiWebInstallationInfo | undefined {
|
||||
if (!isRecord(value)) return undefined;
|
||||
const kind = value["kind"];
|
||||
|
||||
Reference in New Issue
Block a user