Hub stage 1: apps across servers, read-only

hub/apps/matrix reads apps/list and each app's config on every server (the read
token first, the admin token once if a server refuses) and returns per app and server
the version, available update and a config hash, plus whether versions and configs
match and how many JSON leaf paths differ. Config texts never leave the hub. In hub
mode the Apps section has the server selector: All servers shows the matrix with
filters for differing versions, differing configs and updates; one server shows its
list without write actions. The dev mock takes --variant a|b with differing apps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DenozordecandClaude Opus 5.5 committed 2026-10-31 15:46:51 +07:00
1 parent 0ef2d53a65
commit 3d8df08fa0
14 files changed
+1082 -37

No files matched your search

+32
View File
@@ -187,3 +187,35 @@ export function updateApp(
const { path, form } = buildUpload('apps/update', name, file)
return apiRequest(path, { token, form })
}
/*
The hub's matrix of apps over servers (`hub/apps/matrix`, hub/apps-matrix.ts). Only on a
hub. A config is never in it: just a hash per server and the comparison.
*/
export interface MatrixCell {
installed: boolean
version?: string
updateAvailable?: boolean
updateVersion?: string
configStatus: 'none' | 'read' | 'unreadable'
configHash?: string
configError?: string
}
export interface MatrixApp {
name: string
description: string
servers: Record<string, MatrixCell>
configs: 'same' | 'different' | 'single' | 'unknown'
diffCount?: number
versions: 'same' | 'different' | 'single'
}
export interface AppsMatrixData {
servers: { id: string; ok: boolean; error?: string }[]
apps: MatrixApp[]
}
export function getAppsMatrix(token: string | null): Promise<ApiOutcome<{ response: AppsMatrixData }>> {
return apiRequest('hub/apps/matrix', { token })
}