const { useState, useEffect, useRef } = React; // Auth via API key // Inject spinner keyframe if (!document.getElementById("wwyw-spin")) { const s = document.createElement("style"); s.id = "wwyw-spin"; s.textContent = "@keyframes spin { to { transform: rotate(360deg) } } @keyframes pulse { 0%,100%{opacity:.4} 50%{opacity:1} }"; document.head.appendChild(s); } const API = "https://analyzer.wewatchyourwebsite.com/js"; function apiHeaders(extra={}) { const s = getSession(); const h = { ...extra }; if (s && s.apiKey) h["X-API-Key"] = s.apiKey; return h; } const PLANS = [ { id:"basic", name:"Basic", price:49, scans:1, followups:0, fixes:5, color:"#38bdf8", desc:"Single scan + report" }, { id:"standard", name:"Standard", price:99, scans:1, followups:3, fixes:20, color:"#a78bfa", desc:"Full scan + 3 follow-ups", popular:true }, { id:"pro", name:"Professional", price:149, scans:1, followups:4, fixes:999, color:"#f97316", desc:"Full scan + 4 follow-ups + unlimited fixes" }, ]; const SEVERITY_COLOR = { critical:"#ef4444", high:"#f97316", medium:"#eab308", low:"#22c55e", informational: "#94a3b8" }; const SEVERITY_BG = { critical:"#fef2f2", high:"#fff7ed", medium:"#fefce8", low:"#f0fdf4", informational:"#f8fafc" }; const SOURCE_LABEL = { secrets:"Secrets", semgrep:"AST Analysis", dep_audit:"Dependency Audit", llm_review:"LLM Review", ast_scan:"Bundle AST" }; // ── Session helpers ─────────────────────────────────────────────────────────── function getSession() { return JSON.parse(localStorage.getItem("wwyw_session") || "null"); } function setSession(data) { localStorage.setItem("wwyw_session", JSON.stringify(data)); } // ── Auth / Plan Selection ───────────────────────────────────────────────────── function Login({ onAuth }) { const [key, setKey] = useState(""); const [err, setErr] = useState(""); const [checking, setChecking] = useState(false); const session = getSession(); if (session) { onAuth(session); return null; } const doLogin = async () => { if (!key.trim()) { setErr("Please enter your API key"); return; } setChecking(true); setErr(""); try { const res = await fetch(API + "/jobs/auth-check", { headers: { "X-API-Key": key.trim() } }); if (res.status === 403 || res.status === 401) { setErr("Invalid API key"); setChecking(false); return; } const plan = { plan:"api", price:0, scansRemaining:999, fixesRemaining:999, apiKey:key.trim(), purchasedAt:new Date().toISOString() }; setSession(plan); onAuth(plan); } catch(e) { setErr("Connection error"); } setChecking(false); }; return (
WWYW
JavaScript Security Analyzer
{ setKey(e.target.value); setErr(""); }} onKeyDown={e=>e.key==="Enter"&&doLogin()} style={{ width:"100%", padding:"10px 12px", borderRadius:8, outline:"none", boxSizing:"border-box", border:err?"1px solid #ef4444":"1px solid #334155", background:"#0f172a", color:"#f1f5f9", fontSize:14 }} /> {err &&
{err}
}
Contact us to receive an API key
); } function PlanSelector({ onSelect, onBack }) { return (
WWYW Security Analysis
One-time payment. No subscription. Scan your AI-generated app before it goes live.
{PLANS.map(plan => (
{plan.popular && (
MOST POPULAR
)}
{plan.name}
${plan.price} once
{plan.desc}
{[ `1 full security scan`, plan.followups > 0 ? `${plan.followups} follow-up scans` : null, `${plan.fixes === 999 ? "Unlimited" : plan.fixes} AI code fixes`, "Full findings report", "Remediation guidance", plan.id === "pro" ? "Priority support" : null, ].filter(Boolean).map((item, i) => (
{item}
))}
))}
{onBack && (
← Back
)}
Secure payment via Stripe · traef@wewatchyourwebsite.com
); } // ── Status Badge ────────────────────────────────────────────────────────────── function StatusBadge({ status, overall }) { const val = (overall||status||"").toLowerCase(); const cfg = { block:{ bg:"#fef2f2", color:"#ef4444", label:"BLOCK" }, blocked:{ bg:"#fef2f2", color:"#ef4444", label:"BLOCK" }, warn:{ bg:"#fff7ed", color:"#f97316", label:"WARN" }, pass:{ bg:"#f0fdf4", color:"#22c55e", label:"PASS" }, running:{ bg:"#eff6ff", color:"#3b82f6", label:"RUNNING" }, queued:{ bg:"#f8fafc", color:"#94a3b8", label:"QUEUED" }, failed:{ bg:"#fef2f2", color:"#ef4444", label:"FAILED" }, complete:{ bg:"#f0fdf4", color:"#22c55e", label:"DONE" }, }[val] || { bg:"#f8fafc", color:"#94a3b8", label:val?.toUpperCase()||"?" }; return {cfg.label}; } // ── Submit Panel ────────────────────────────────────────────────────────────── function SubmitPanel({ onSubmit, loading, session }) { const [tab, setTab] = useState("url"); const [url, setUrl] = useState(""); const [bulk, setBulk] = useState(""); const [file, setFile] = useState(null); const fileRef = useRef(); const canScan = session.scansRemaining > 0; const submit = () => { if (!canScan) return; if (tab==="url" && url.trim()) onSubmit({ type:"url", value:url.trim() }); if (tab==="bulk") { const urls=bulk.split("\n").map(s=>s.trim()).filter(Boolean); if(urls.length) onSubmit({type:"bulk",value:urls}); } if (tab==="zip" && file) onSubmit({ type:"zip", value:file }); }; const tabs = [{ id:"url", label:"URL" }, { id:"bulk", label:"Bulk" }, { id:"zip", label:"ZIP" }]; return (
{/* Scan credits */}
Scans remaining: {session.scansRemaining}
Fixes remaining: {session.fixesRemaining===999?"∞":session.fixesRemaining}
{!canScan && (
No scans remaining.{" "} { localStorage.removeItem("wwyw_session"); window.location.reload(); }}> Upgrade plan
)}
{tabs.map(t=>( ))}
{tab==="url" && (
setUrl(e.target.value)} onKeyDown={e=>e.key==="Enter"&&submit()} placeholder="github.com/user/repo or https://site.com" style={{ flex:1, padding:"8px 11px", borderRadius:8, border:"1px solid #334155", background:"#0f172a", color:"#f1f5f9", fontSize:12, outline:"none" }} />
)} {tab==="bulk" && (