using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Json; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using StellaOps.Cli.Services.Models; namespace StellaOps.Cli.Services; /// /// HTTP client for Authority console endpoints (CLI-TEN-47-001, CLI-TEN-49-001). /// internal sealed class AuthorityConsoleClient : IAuthorityConsoleClient { private readonly HttpClient _httpClient; private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web); public AuthorityConsoleClient(HttpClient httpClient) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); } public async Task> ListTenantsAsync(string tenant, CancellationToken cancellationToken) { using var request = new HttpRequestMessage(HttpMethod.Get, "console/tenants"); if (!string.IsNullOrWhiteSpace(tenant)) { request.Headers.Add("X-StellaOps-Tenant", tenant.Trim().ToLowerInvariant()); } using var response = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var result = await response.Content .ReadFromJsonAsync(cancellationToken: cancellationToken) .ConfigureAwait(false); return result?.Tenants ?? Array.Empty(); } public async Task MintTokenAsync(TokenMintRequest request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "console/token/mint") { Content = JsonContent.Create(request, options: JsonOptions) }; if (!string.IsNullOrWhiteSpace(request.Tenant)) { httpRequest.Headers.Add("X-StellaOps-Tenant", request.Tenant.Trim().ToLowerInvariant()); } using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var result = await response.Content .ReadFromJsonAsync(JsonOptions, cancellationToken) .ConfigureAwait(false); return result ?? throw new InvalidOperationException("Token mint response was empty."); } public async Task DelegateTokenAsync(TokenDelegateRequest request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "console/token/delegate") { Content = JsonContent.Create(request, options: JsonOptions) }; if (!string.IsNullOrWhiteSpace(request.Tenant)) { httpRequest.Headers.Add("X-StellaOps-Tenant", request.Tenant.Trim().ToLowerInvariant()); } using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var result = await response.Content .ReadFromJsonAsync(JsonOptions, cancellationToken) .ConfigureAwait(false); return result ?? throw new InvalidOperationException("Token delegation response was empty."); } public async Task IntrospectTokenAsync(string? tenant, CancellationToken cancellationToken) { using var httpRequest = new HttpRequestMessage(HttpMethod.Post, "console/token/introspect"); if (!string.IsNullOrWhiteSpace(tenant)) { httpRequest.Headers.Add("X-StellaOps-Tenant", tenant.Trim().ToLowerInvariant()); } using var response = await _httpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { return null; } return await response.Content .ReadFromJsonAsync(JsonOptions, cancellationToken) .ConfigureAwait(false); } }