1import { CLOUD_URL } from "./firebase-config.js?v=radar-20260626"; 2 3const BILLING_REQUEST_TIMEOUT_MS = 10000; 4 5async function fetchBilling(path, init) { 6 const controller = new AbortController(); 7 const timeoutId = setTimeout( 8 () => controller.abort(), 9 BILLING_REQUEST_TIMEOUT_MS, 10 ); 11 12 try { 13 return await fetch(`${CLOUD_URL}${path}`, { 14 ...init, 15 signal: controller.signal, 16 }); 17 } finally { 18 clearTimeout(timeoutId); 19 } 20} 21 22export async function getFirebaseIdToken(user, { forceRefresh = false } = {}) { 23 return user.getIdToken(forceRefresh); 24} 25 26export async function fetchBillingContext(token) { 27 let response; 28 try { 29 response = await fetchBilling("/billing/context", { 30 method: "POST", 31 headers: { 32 Authorization: `Bearer ${token}`, 33 "Content-Type": "application/json", 34 }, 35 body: "{}", 36 }); 37 } catch (error) { 38 console.error("[Billing] Context request failed:", error); 39 return null; 40 } 41 42 if (!response.ok) { 43 console.warn("[Billing] Context request failed:", response.status); 44 return null; 45 } 46 47 return response.json().catch(() => null); 48} 49 50export async function fetchBillingContextForUser(user) { 51 let token; 52 try { 53 token = await getFirebaseIdToken(user); 54 } catch (error) { 55 console.error("[Billing] Failed to read Firebase ID token:", error); 56 return null; 57 } 58 59 return fetchBillingContext(token); 60} 61 62export async function fetchSubscriptionPrices() { 63 const response = await fetchBilling("/billing/prices", { 64 method: "GET", 65 headers: { 66 Accept: "application/json", 67 }, 68 }); 69 70 if (!response.ok) { 71 throw new Error(`Price request failed with status ${response.status}`); 72 } 73 74 return response.json(); 75} 76 77export async function createBillingPortalSession(token, returnUrl) { 78 return fetchBilling("/billing/portal-session", { 79 method: "POST", 80 headers: { 81 Authorization: `Bearer ${token}`, 82 "Content-Type": "application/json", 83 }, 84 body: JSON.stringify({ returnUrl }), 85 }); 86} 87 88export async function createSubscriptionCheckoutSession( 89 token, 90 { successUrl, cancelUrl, priceKey } = {}, 91) { 92 return fetchBilling("/billing/checkout-session", { 93 method: "POST", 94 headers: { 95 Authorization: `Bearer ${token}`, 96 "Content-Type": "application/json", 97 }, 98 body: JSON.stringify({ 99 ...(successUrl ? { successUrl } : {}), 100 ...(cancelUrl ? { cancelUrl } : {}), 101 ...(priceKey ? { priceKey } : {}), 102 }), 103 }); 104}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.