From 6aea72e2948b7e3b93b3d41ed5bd99a4eb5bbfa8 Mon Sep 17 00:00:00 2001 From: Angello Picasso Date: Mon, 14 Sep 2026 01:10:19 +0000 Subject: [PATCH] fix(plugin-quota): preserve mapped summaries --- .../api/handlers/management/plugin_quota.go | 28 +++++++++++++++---- .../handlers/management/plugin_quota_test.go | 4 +++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/internal/api/handlers/management/plugin_quota.go b/internal/api/handlers/management/plugin_quota.go index 6d66c7134..092284545 100644 --- a/internal/api/handlers/management/plugin_quota.go +++ b/internal/api/handlers/management/plugin_quota.go @@ -474,6 +474,7 @@ func (h *Handler) executeQuotaProbe(c *gin.Context, auth *coreauth.Auth, probe m if errMap != nil { return pluginapi.QuotaFetchResponse{}, true, fmt.Errorf("probe response mapping failed: %w", errMap) } + mappedResp.Summary = filterUsableQuotaSummary(respBytes) if mappedResp.ServerTimeOffsetMs == 0 { mappedResp.ServerTimeOffsetMs = serverOffsetMs } @@ -543,12 +544,25 @@ func (h *Handler) executeQuotaProbe(c *gin.Context, auth *coreauth.Auth, probe m } func filterUsableQuotaSummary(raw []byte) []pluginapi.QuotaMetric { - rawSummary := gjson.GetBytes(raw, "summary") - if !rawSummary.IsArray() { + var rawQuota map[string]json.RawMessage + if err := json.Unmarshal(raw, &rawQuota); err != nil { return nil } - usable := make([]pluginapi.QuotaMetric, 0, len(rawSummary.Array())) - for _, rawMetric := range rawSummary.Array() { + rawSummary, ok := rawQuota["summary"] + if !ok { + for key, value := range rawQuota { + if strings.EqualFold(key, "summary") { + rawSummary = value + break + } + } + } + summaryResult := gjson.ParseBytes(rawSummary) + if !summaryResult.IsArray() { + return nil + } + usable := make([]pluginapi.QuotaMetric, 0, len(summaryResult.Array())) + for _, rawMetric := range summaryResult.Array() { keyResult := rawMetric.Get("key") labelResult := rawMetric.Get("label") key := strings.TrimSpace(keyResult.String()) @@ -566,9 +580,11 @@ func filterUsableQuotaSummary(raw []byte) []pluginapi.QuotaMetric { metric.Unit = strings.TrimSpace(unitResult.String()) } if formatResult := rawMetric.Get("format"); formatResult.Type == gjson.String { - metric.Format = strings.TrimSpace(formatResult.String()) + if format := strings.TrimSpace(formatResult.String()); format == "number" || format == "currency" { + metric.Format = format + } } - if currencyResult := rawMetric.Get("currency"); currencyResult.Type == gjson.String { + if currencyResult := rawMetric.Get("currency"); metric.Format == "currency" && currencyResult.Type == gjson.String { metric.Currency = strings.TrimSpace(currencyResult.String()) } usable = append(usable, metric) diff --git a/internal/api/handlers/management/plugin_quota_test.go b/internal/api/handlers/management/plugin_quota_test.go index fbda9ec30..0a570d117 100644 --- a/internal/api/handlers/management/plugin_quota_test.go +++ b/internal/api/handlers/management/plugin_quota_test.go @@ -663,6 +663,7 @@ func TestFetchCredentialQuota_DeclarativeProbeWithMapping(t *testing.T) { // Upstream returns raw non-normalized billing format _, _ = w.Write([]byte(`{ "user": {"tier": "Enterprise"}, + "Summary": [{"key": "credits_used", "label": "Credits used", "value": 40}], "packages": [ { "period": "monthly", @@ -724,6 +725,9 @@ func TestFetchCredentialQuota_DeclarativeProbeWithMapping(t *testing.T) { if quotaResp.Subscription == nil || quotaResp.Subscription.Plan != "Enterprise" { t.Fatalf("unexpected plan: %+v", quotaResp.Subscription) } + if len(quotaResp.Summary) != 1 || quotaResp.Summary[0].Key != "credits_used" || quotaResp.Summary[0].Value != 40 { + t.Fatalf("unexpected summary: %+v", quotaResp.Summary) + } if len(quotaResp.Groups) != 1 || len(quotaResp.Groups[0].Buckets) != 1 { t.Fatalf("unexpected groups: %+v", quotaResp.Groups) }