From a0005b1e376a42fa33fb6e9bc9d9d7260f61e50a Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 20 May 2026 21:08:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=89=8D=E7=AB=AF=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/__tests__/paymentShell.test.ts | 17 +++++++++++++ .../subscriptions/SubscriptionsPageClient.tsx | 25 +++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/frontend/components/account/__tests__/paymentShell.test.ts b/frontend/components/account/__tests__/paymentShell.test.ts index a46d4d31..980ccd30 100644 --- a/frontend/components/account/__tests__/paymentShell.test.ts +++ b/frontend/components/account/__tests__/paymentShell.test.ts @@ -25,6 +25,16 @@ export function runTests() { path.join(projectRoot, "app", "api", "analytics", "events", "route.ts"), "utf8", ); + const subscriptionsPageSource = fs.readFileSync( + path.join( + projectRoot, + "components", + "ops", + "subscriptions", + "SubscriptionsPageClient.tsx", + ), + "utf8", + ); assert( accountCenterSource.includes( @@ -66,4 +76,11 @@ export function runTests() { accountCenterSource.includes('trackAppEvent("dashboard_active"'), "account center must emit signup_completed and dashboard_active so the ops funnel has top-of-funnel data", ); + assert( + subscriptionsPageSource.includes("getSupabaseBrowserClient") && + subscriptionsPageSource.includes("Authorization") && + subscriptionsPageSource.includes("/api/ops/subscriptions/grant") && + subscriptionsPageSource.includes("/api/ops/subscriptions/extend"), + "ops manual subscription grant/extend must send the Supabase bearer token to avoid 401 when route cookies are stale", + ); } diff --git a/frontend/components/ops/subscriptions/SubscriptionsPageClient.tsx b/frontend/components/ops/subscriptions/SubscriptionsPageClient.tsx index 61fcc542..78dad82b 100644 --- a/frontend/components/ops/subscriptions/SubscriptionsPageClient.tsx +++ b/frontend/components/ops/subscriptions/SubscriptionsPageClient.tsx @@ -4,6 +4,27 @@ import { useState } from "react"; import { ScrollText, Coins, Minus } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { + getSupabaseBrowserClient, + hasSupabasePublicEnv, +} from "@/lib/supabase/client"; + +async function buildOpsAuthHeaders() { + const headers: Record = { + "Content-Type": "application/json", + }; + if (!hasSupabasePublicEnv()) return headers; + try { + const { + data: { session }, + } = await getSupabaseBrowserClient().auth.getSession(); + const token = String(session?.access_token || "").trim(); + if (token) headers.Authorization = `Bearer ${token}`; + } catch { + // Route cookies may still authenticate the request. + } + return headers; +} export function SubscriptionsPageClient() { const [email, setEmail] = useState(""); @@ -21,7 +42,7 @@ export function SubscriptionsPageClient() { try { const res = await fetch("/api/ops/subscriptions/grant", { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: await buildOpsAuthHeaders(), body: JSON.stringify({ email: email.trim(), plan_code: planCode, @@ -56,7 +77,7 @@ export function SubscriptionsPageClient() { try { const res = await fetch("/api/ops/subscriptions/extend", { method: "POST", - headers: { "Content-Type": "application/json" }, + headers: await buildOpsAuthHeaders(), body: JSON.stringify({ email: email.trim(), additional_days: extendDays }), }); if (res.ok) {