All checks were successful
Active-sessions table with consent-state badges, viewer-token Join, and disconnect, built on the v2 session API and existing UI primitives. - Sessions table: machine, mode (managed/attended), consent badge (granted/pending+pulse/denied/not_required), viewers, started, duration, status. Sticky header, skeleton load, empty/error states. - Join action mints a session-scoped viewer token (POST /api/sessions/:id/viewer-token) and reveals it with the /ws/viewer relay URL and copy buttons. The static viewer.html is intentionally not targeted: it sends the raw login JWT, which the v2 viewer plane rejects. In-dashboard web viewer ships in a later pass. - Authz split mirrors the server mint gate: admin or control permission gets Control; view permission gets View only; neither hides the action. Server remains authoritative; the minted token carries the signed access claim. - Disconnect via confirm dialog (DELETE /api/sessions/:id), invalidates the sessions query. List polls every 8s so consent transitions surface. Passed Code Review (no blockers) and local gates (tsc/lint/build green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
37 lines
1.4 KiB
TypeScript
37 lines
1.4 KiB
TypeScript
import { http } from "./client";
|
|
import type { Session, ViewerTokenResponse } from "./types";
|
|
|
|
/**
|
|
* GET /api/sessions — all live sessions known to the relay's in-memory session
|
|
* manager (active + offline-persistent). Requires an authenticated dashboard
|
|
* JWT; any authenticated user may list.
|
|
*/
|
|
export function listSessions(signal?: AbortSignal): Promise<Session[]> {
|
|
return http.get<Session[]>("/api/sessions", signal);
|
|
}
|
|
|
|
/**
|
|
* POST /api/sessions/:id/viewer-token — mint a short-lived, session-scoped
|
|
* viewer token. The server decides the access mode from the caller's
|
|
* permissions: admin or `control` permission gets a `control` token, otherwise
|
|
* a `view_only` token. A caller with neither `control` nor `view` gets 403.
|
|
* The access mode is stamped into the signed token; this response only echoes
|
|
* it. (See server/src/api/sessions.rs::mint_viewer_token.)
|
|
*/
|
|
export function mintViewerToken(
|
|
sessionId: string,
|
|
): Promise<ViewerTokenResponse> {
|
|
return http.post<ViewerTokenResponse>(
|
|
`/api/sessions/${encodeURIComponent(sessionId)}/viewer-token`,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* DELETE /api/sessions/:id — disconnect/end a live session. The relay sends a
|
|
* Disconnect to the agent. Returns 200 on success, 404 if the session is not
|
|
* found. Requires an authenticated dashboard JWT (not admin-gated server-side).
|
|
*/
|
|
export function endSession(sessionId: string): Promise<void> {
|
|
return http.del<void>(`/api/sessions/${encodeURIComponent(sessionId)}`);
|
|
}
|