/** * AT Protocol Auth Provider Admin Components * * Provides LoginForm and SetupStep components for the pluggable auth system. * These are imported at build time via the virtual:emdash/auth-providers module. */ import { Button, Input } from "@cloudflare/kumo"; import * as React from "react"; // ============================================================================ // Shared icon // ============================================================================ function AtprotoIcon({ className }: { className?: string }) { return ( ); } // ============================================================================ // LoginButton — compact button shown in the provider grid // ============================================================================ export function LoginButton() { return ( Atmosphere ); } // ============================================================================ // LoginForm — expanded form shown when LoginButton is clicked // ============================================================================ export function LoginForm() { const [handle, setHandle] = React.useState(""); const [isLoading, setIsLoading] = React.useState(false); const [error, setError] = React.useState(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!handle.trim()) return; setIsLoading(true); setError(null); try { const response = await fetch("/_emdash/api/auth/atproto/login", { method: "POST", headers: { "Content-Type": "application/json", "X-EmDash-Request": "1", }, body: JSON.stringify({ handle: handle.trim() }), }); if (!response.ok) { const body: { error?: { message?: string } } = await response.json().catch(() => ({})); throw new Error(body?.error?.message || "Failed to start AT Protocol login"); } const result: { data: { url: string } } = await response.json(); window.location.href = result.data.url; } catch (err) { setError(err instanceof Error ? err.message : "Failed to start AT Protocol login"); setIsLoading(false); } }; return ( setHandle(e.target.value)} placeholder="you.bsky.social" disabled={isLoading} /> {error && ( {error} )} {isLoading ? "Connecting..." : "Sign in"} ); } // ============================================================================ // SetupStep — shown in the setup wizard // ============================================================================ export function SetupStep({ onComplete }: { onComplete: () => void }) { const [handle, setHandle] = React.useState(""); const [isLoading, setIsLoading] = React.useState(false); const [error, setError] = React.useState(null); // Suppress unused variable warning — onComplete is called after redirect void onComplete; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!handle.trim()) return; setIsLoading(true); setError(null); try { const response = await fetch("/_emdash/api/setup/atproto-admin", { method: "POST", headers: { "Content-Type": "application/json", "X-EmDash-Request": "1", }, body: JSON.stringify({ handle: handle.trim() }), }); if (!response.ok) { const body: { error?: { message?: string } } = await response.json().catch(() => ({})); throw new Error(body?.error?.message || "Failed to start AT Protocol login"); } const result: { data: { url: string } } = await response.json(); // Redirect to PDS authorization page — onComplete will be called after redirect back window.location.href = result.data.url; } catch (err) { setError(err instanceof Error ? err.message : "Failed to start AT Protocol login"); setIsLoading(false); } }; return ( Atmosphere Sign in with your Bluesky/Atmosphere handle setHandle(e.target.value)} placeholder="you.bsky.social" disabled={isLoading} className="w-full" /> {error && ( {error} )} {isLoading ? "Connecting..." : "Sign in"} ); }
Atmosphere
Sign in with your Bluesky/Atmosphere handle