Files
guru-connect/dashboard/src/api/sessions.ts
Mike Swanson 6ecb937eb6
All checks were successful
Build and Test / Build Agent (Windows) (push) Successful in 7m9s
Build and Test / Build Server (Linux) (push) Successful in 10m41s
Build and Test / Security Audit (push) Successful in 4m25s
Build and Test / Build Summary (push) Successful in 10s
feat(dashboard): GuruConnect v2 Sessions view (pass 2)
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>
2026-05-30 13:12:04 -07:00

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)}`);
}