import { useCallback, useEffect, useRef, useState } from 'react' import relayAdmin from '@/services/relay-admin.service' import { useRelayAdmin } from '@/providers/RelayAdminProvider' import { useNostr } from '@/providers/NostrProvider' import { Button } from '@/components/ui/button' import { cn } from '@/lib/utils' import { toast } from 'sonner' interface SprocketStatus { is_running: boolean pid?: number script_exists: boolean } interface SprocketVersion { name: string modified: string is_current: boolean } export default function SprocketTab() { const { pubkey } = useNostr() const { isOwner, userRole } = useRelayAdmin() const [script, setScript] = useState('') const [status, setStatus] = useState(null) const [versions, setVersions] = useState([]) const [isLoading, setIsLoading] = useState(false) const [uploadFile, setUploadFile] = useState(null) const fileInputRef = useRef(null) const loadStatus = useCallback(async () => { try { const data = (await relayAdmin.loadSprocketStatus()) as unknown as SprocketStatus setStatus(data) } catch (e) { console.error('Failed to load sprocket status:', e) } }, []) const loadScript = useCallback(async () => { setIsLoading(true) try { const text = await relayAdmin.loadSprocketScript() setScript(text) toast.success('Script loaded') } catch (e) { toast.error(`Failed to load script: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } }, []) const loadVersions = useCallback(async () => { try { const data = (await relayAdmin.loadSprocketVersions()) as unknown as SprocketVersion[] setVersions(data) } catch (e) { toast.error(`Failed to load versions: ${e instanceof Error ? e.message : String(e)}`) } }, []) useEffect(() => { if (!isOwner) return loadStatus() loadScript() loadVersions() }, [isOwner, loadStatus, loadScript, loadVersions]) const handleSave = async () => { setIsLoading(true) try { await relayAdmin.saveSprocketScript(script) toast.success('Script saved and updated') await loadStatus() await loadVersions() } catch (e) { toast.error(`Save failed: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } } const handleRestart = async () => { setIsLoading(true) try { await relayAdmin.restartSprocket() toast.success('Sprocket restarted') await loadStatus() } catch (e) { toast.error(`Restart failed: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } } const handleDelete = async () => { if (!confirm('Delete the sprocket script? This cannot be undone.')) return setIsLoading(true) try { await relayAdmin.deleteSprocket() setScript('') toast.success('Script deleted') await loadStatus() await loadVersions() } catch (e) { toast.error(`Delete failed: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } } const handleFileSelect = (e: React.ChangeEvent) => { const file = e.target.files?.[0] || null setUploadFile(file) } const handleUpload = async () => { if (!uploadFile) return setIsLoading(true) try { const text = await uploadFile.text() setScript(text) await relayAdmin.saveSprocketScript(text) toast.success('Script uploaded and updated') setUploadFile(null) if (fileInputRef.current) fileInputRef.current.value = '' await loadStatus() await loadVersions() } catch (e) { toast.error(`Upload failed: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } } const handleLoadVersion = async (version: SprocketVersion) => { setIsLoading(true) try { const text = await relayAdmin.loadSprocketVersion(version.name) setScript(text) toast.success(`Loaded version: ${version.name}`) } catch (e) { toast.error(`Failed to load version: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } } const handleDeleteVersion = async (versionName: string) => { if (!confirm(`Delete version "${versionName}"?`)) return setIsLoading(true) try { await relayAdmin.deleteSprocketVersion(versionName) toast.success(`Version "${versionName}" deleted`) await loadVersions() } catch (e) { toast.error(`Failed to delete version: ${e instanceof Error ? e.message : String(e)}`) } finally { setIsLoading(false) } } if (!pubkey) { return (

Please log in to access sprocket management.

) } if (!isOwner) { return (

Owner permission required for sprocket management.

Set the ORLY_OWNERS environment variable with your npub when starting the relay.

Current role: {userRole || 'none'}

) } return (

Sprocket Script Management

{/* Script Editor Section */}

Script Editor

{/* Upload */}
{/* Status */}
Status {status?.is_running ? 'Running' : 'Stopped'}
{status?.pid != null && (
PID {status.pid}
)}
Script {status?.script_exists ? 'Exists' : 'Not found'}
{/* Editor */}