// Cloudflare Billing Manager - Fixed Stripe PK Validation // Global API Key Auth + Account Auto-Discovery + Billing + Payment Methods const CLOUDFLARE_API = "https://api.cloudflare.com/client/v4"; export default { async fetch(request, env, ctx) { const url = new URL(request.url); const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, X-CF-Email, X-CF-Key", }; if (request.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { if (url.pathname === "/" && request.method === "GET") { return new Response(getDashboardHTML(), { headers: { "Content-Type": "text/html; charset=utf-8", ...corsHeaders }, }); } const cfEmail = request.headers.get("X-CF-Email"); const cfKey = request.headers.get("X-CF-Key"); if (!cfEmail || !cfKey) { return Response.json( { ok: false, error: "Missing X-CF-Email or X-CF-Key header" }, { status: 401, headers: corsHeaders } ); } const authHeaders = { "X-Auth-Email": cfEmail, "X-Auth-Key": cfKey, "Content-Type": "application/json", }; const accountId = await resolveAccountId(authHeaders); if (url.pathname === "/api/accounts" && request.method === "GET") { const data = await cfFetch(authHeaders, "/accounts?per_page=50"); return Response.json({ data: data.result || [] }, { headers: corsHeaders }); } if (url.pathname === "/api/billing" && request.method === "GET") { const billing = await cfFetch( authHeaders, `/accounts/${accountId}/billing/history?per_page=50` ); return Response.json( { source: "api", accountId, data: billing.result || [] }, { headers: corsHeaders } ); } if (url.pathname === "/api/profile" && request.method === "GET") { const profile = await cfFetch( authHeaders, `/accounts/${accountId}/billing/profile` ); return Response.json( { ok: true, data: profile.result }, { headers: corsHeaders } ); } if (url.pathname === "/api/profile" && request.method === "PUT") { const body = await request.json(); const res = await fetch( `${CLOUDFLARE_API}/accounts/${accountId}/billing/profile`, { method: "PUT", headers: authHeaders, body: JSON.stringify(body), } ); const json = await res.json(); if (!res.ok || json.success === false) { return Response.json( { ok: false, error: "Profile update failed", detail: json }, { status: res.status, headers: corsHeaders } ); } return Response.json({ ok: true, result: json.result }, { headers: corsHeaders }); } if (url.pathname === "/api/payment-methods" && request.method === "GET") { const pms = await cfFetch( authHeaders, `/accounts/${accountId}/payment-methods` ); return Response.json( { ok: true, accountId, data: pms.result || [] }, { headers: corsHeaders } ); } if ( url.pathname.startsWith("/api/payment-methods/") && url.pathname.endsWith("/set-as-default") && request.method === "POST" ) { const pmId = url.pathname.split("/")[3]; const res = await fetch( `${CLOUDFLARE_API}/accounts/${accountId}/payment-methods/${pmId}/set-as-default`, { method: "POST", headers: authHeaders } ); if (!res.ok && res.status !== 204) { const errText = await res.text(); return Response.json( { ok: false, error: `set-as-default failed: ${res.status}`, detail: errText }, { status: res.status, headers: corsHeaders } ); } return Response.json( { ok: true, action: "set-as-default", pmId }, { headers: corsHeaders } ); } if (url.pathname === "/api/payment-methods/events" && request.method === "POST") { const body = await request.json(); const res = await fetch( `${CLOUDFLARE_API}/accounts/${accountId}/payment-methods/events`, { method: "POST", headers: authHeaders, body: JSON.stringify({ operation_id: crypto.randomUUID(), action: body.action || "backup_added", payment_method_id: body.payment_method_id, }), } ); return Response.json( { ok: true, status: res.status }, { headers: corsHeaders } ); } if (url.pathname === "/api/payment-intent" && request.method === "POST") { const intent = await cfFetch( authHeaders, `/accounts/${accountId}/billing/profile/payment-method`, "POST" ); return Response.json( { ok: true, accountId, client_secret: intent.result?.client_secret, intent_type: intent.result?.intent_type, }, { headers: corsHeaders } ); } if (url.pathname === "/api/payment-method/attach" && request.method === "POST") { const body = await request.json(); if (!body.pmId) { return Response.json( { ok: false, error: "Missing pmId" }, { status: 400, headers: corsHeaders } ); } const profileRes = await fetch( `${CLOUDFLARE_API}/accounts/${accountId}/billing/profile`, { method: "PUT", headers: authHeaders, body: JSON.stringify({ account_type: body.account_type || "personal", first_name: body.first_name || "", last_name: body.last_name || "", address: body.address || "", address2: body.address2 || "", city: body.city || "", country: body.country || "ID", state: body.state || "", zipcode: body.zipcode || "", payment_gateway: "stripe", payment_nonce: body.pmId, }), } ); const profileJson = await profileRes.json(); const defRes = await fetch( `${CLOUDFLARE_API}/accounts/${accountId}/payment-methods/${body.pmId}/set-as-default`, { method: "POST", headers: authHeaders } ); await fetch( `${CLOUDFLARE_API}/accounts/${accountId}/payment-methods/events`, { method: "POST", headers: authHeaders, body: JSON.stringify({ operation_id: crypto.randomUUID(), action: "backup_added", payment_method_id: body.pmId, }), } ); return Response.json( { ok: true, profile: profileJson.result, setAsDefault: defRes.ok || defRes.status === 204, }, { headers: corsHeaders } ); } return new Response("Not Found", { status: 404, headers: corsHeaders }); } catch (err) { return Response.json( { ok: false, error: err.message, code: err.code || "UNKNOWN", detail: err.detail || null, }, { status: 500, headers: corsHeaders } ); } }, }; async function resolveAccountId(authHeaders) { const accounts = await cfFetch(authHeaders, "/accounts?per_page=50"); if (!accounts.result?.length) { const e = new Error("No accounts accessible with this token/key"); e.code = "NO_ACCOUNT"; throw e; } return accounts.result[0].id; } async function cfFetch(headers, path, method = "GET", body = null) { const opts = { method, headers }; if (body) opts.body = JSON.stringify(body); const res = await fetch(`${CLOUDFLARE_API}${path}`, opts); const text = await res.text(); if (res.status === 204) return { success: true, result: null }; let json; try { json = JSON.parse(text); } catch { const e = new Error(`Non-JSON response (${res.status})`); e.code = `CF_${res.status}`; e.detail = text.slice(0, 500); throw e; } if (!res.ok || json.success === false) { const e = new Error(`Cloudflare API error (${res.status})`); e.code = `CF_${res.status}`; e.detail = JSON.stringify(json.errors || json); throw e; } return json; } function getDashboardHTML() { return `