'use client'; import React, { useState, useEffect } from 'react'; import { Secret } from '@/lib/vfs/types'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Loader2, AlertCircle, Eye, EyeOff, Info } from 'lucide-react'; interface SecretEditorProps { secret: Secret | null; isOpen: boolean; onClose: () => void; onSave: (data: { name: string; value?: string; description?: string }) => Promise; } export function SecretEditor({ secret, isOpen, onClose, onSave, }: SecretEditorProps) { const [name, setName] = useState(secret?.name || ''); const [value, setValue] = useState(''); const [description, setDescription] = useState(secret?.description || ''); const [showValue, setShowValue] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (isOpen) { setName(secret?.name || ''); setValue(''); setDescription(secret?.description || ''); setShowValue(false); setError(null); } }, [secret, isOpen]); const handleNameChange = (e: React.ChangeEvent) => { // Convert to SCREAMING_SNAKE_CASE const newValue = e.target.value .toUpperCase() .replace(/[^A-Z0-9_]/g, '') .replace(/^[0-9]+/, ''); // Remove leading numbers setName(newValue); }; const handleSave = async () => { setError(null); // Basic validation if (!name.trim()) { setError('Secret name is required'); return; } // Validate SCREAMING_SNAKE_CASE if (!/^[A-Z][A-Z0-9_]*$/.test(name)) { setError('Name must be SCREAMING_SNAKE_CASE (uppercase letters, numbers, underscores; must start with letter)'); return; } // Value required for new secrets if (!secret && !value.trim()) { setError('Secret value is required'); return; } setSaving(true); try { await onSave({ name: name.trim(), value: value.trim() || undefined, description: description.trim() || undefined, }); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to save secret'); } finally { setSaving(false); } }; return ( {secret ? 'Edit Secret' : 'Create Secret'} Store sensitive values like API keys securely. Edge functions can access them via secrets.get('{name || 'NAME'}').
{/* Name */}

Use SCREAMING_SNAKE_CASE (e.g., API_KEY, SENDGRID_TOKEN)

{/* Value */}
setValue(e.target.value)} placeholder={secret ? 'Enter new value to change...' : 'sk_live_...'} className="pr-10 font-mono" />

{secret ? 'Leave empty to keep the existing value' : 'This value will be encrypted and never displayed again'}

{/* Description */}
setDescription(e.target.value)} placeholder="Production Stripe API key" />
{/* Usage Reference */}
Usage in Edge Functions
{`// Get secret value
const apiKey = secrets.get('${name || 'STRIPE_API_KEY'}');

// Check if secret exists
if (secrets.has('${name || 'STRIPE_API_KEY'}')) {
  // Use the secret
}

// List all available secrets
const allSecrets = secrets.list(); // ['${name || 'STRIPE_API_KEY'}', ...]`}
            
{/* Error */} {error && (
{error}
)}
{/* Footer */}
); }