BackupImport
Component for importing Bitcoin wallet backups from various formats
BackupImport combines native HTML file input with Bitcoin backup processing, providing a streamlined interface for importing encrypted wallet backups with validation, profile synchronization, and secure file handling.
Basic Import
With Custom Styling
Demo Note: This demonstrates the backup import interface. In a real application, uploaded files would be validated and processed securely.
Installation
npx bigblocks add backup-import
Import
import { BackupImport } from 'bigblocks';
This component extends native HTML file input functionality with Bitcoin-specific backup processing.
Props
Prop | Type | Required | Default | Description |
---|---|---|---|---|
onImport | (file: File) => Promise<void> | void | Yes | - | Handler for file import |
disabled | boolean | No | false | Disable the import button |
className | string | No | - | Additional CSS classes |
showLabel | boolean | No | true | Show the label text |
enableProfileSync | boolean | No | false | Enable profile synchronization |
maxDiscoveryAttempts | number | No | 3 | Max attempts for profile discovery |
onImportSuccess | () => void | No | - | Callback when import succeeds |
Basic Usage
import { BackupImport } from 'bigblocks';
export default function RestorePage() {
const handleImport = async (file: File) => {
try {
// Process the backup file
const content = await file.text();
// Your backup processing logic
await processBackup(content);
console.log('Backup imported successfully');
} catch (error) {
console.error('Import failed:', error);
throw error; // Re-throw to show error in UI
}
};
return (
<BackupImport
onImport={handleImport}
onImportSuccess={() => {
console.log('Import completed!');
}}
/>
);
}
Advanced Usage
With Authentication Manager
import { BackupImport } from 'bigblocks';
import { useAuthManager } from '@/hooks/useAuthManager';
export default function AuthBackupImport() {
const authManager = useAuthManager();
return (
<BackupImport
onImport={async (file) => {
await authManager.importBackup(file);
}}
onImportSuccess={() => {
router.push('/dashboard');
}}
/>
);
}
With Profile Sync
import { BackupImport } from 'bigblocks';
export default function ProfileSyncImport() {
return (
<BackupImport
onImport={handleBackupImport}
enableProfileSync={true}
maxDiscoveryAttempts={5}
onImportSuccess={() => {
toast.success('Backup imported with profile sync');
}}
/>
);
}
Disabled State
import { BackupImport } from 'bigblocks';
import { useState } from 'react';
export default function ConditionalImport() {
const [isProcessing, setIsProcessing] = useState(false);
return (
<BackupImport
onImport={async (file) => {
setIsProcessing(true);
try {
await processBackupFile(file);
} finally {
setIsProcessing(false);
}
}}
disabled={isProcessing}
showLabel={!isProcessing}
/>
);
}
Custom Styling
import { BackupImport } from 'bigblocks';
export default function StyledImport() {
return (
<BackupImport
onImport={handleImport}
className="border-2 border-dashed border-orange-300 p-6 rounded-lg"
showLabel={true}
/>
);
}
Common Patterns
In Restore Flow
import { BackupImport } from 'bigblocks';
import { useState } from 'react';
export function RestoreFlow() {
const [step, setStep] = useState<'import' | 'password' | 'complete'>('import');
const [backupFile, setBackupFile] = useState<File | null>(null);
return (
<div className="max-w-md mx-auto">
{step === 'import' && (
<div>
<h2 className="text-xl font-bold mb-4">Import Your Backup</h2>
<BackupImport
onImport={async (file) => {
setBackupFile(file);
setStep('password');
}}
/>
</div>
)}
{step === 'password' && backupFile && (
<div>
<h2 className="text-xl font-bold mb-4">Enter Password</h2>
<PasswordInput
onSubmit={async (password) => {
await decryptAndImport(backupFile, password);
setStep('complete');
}}
/>
</div>
)}
{step === 'complete' && (
<div>
<h2 className="text-xl font-bold mb-4">Import Complete!</h2>
<button onClick={() => router.push('/dashboard')}>
Go to Dashboard
</button>
</div>
)}
</div>
);
}
With Error Handling
import { BackupImport } from 'bigblocks';
import { useState } from 'react';
export function ImportWithErrors() {
const [error, setError] = useState<string | null>(null);
return (
<div>
{error && (
<div className="bg-red-100 text-red-700 p-3 rounded mb-4">
{error}
</div>
)}
<BackupImport
onImport={async (file) => {
setError(null);
try {
// Validate file
if (!file.name.match(/\.(txt|json|enc)$/)) {
throw new Error('Invalid file type. Please select a backup file.');
}
if (file.size > 10 * 1024 * 1024) {
throw new Error('File too large. Maximum size is 10MB.');
}
await processBackup(file);
} catch (err) {
setError(err.message);
throw err; // Re-throw for component error handling
}
}}
onImportSuccess={() => {
setError(null);
toast.success('Backup imported successfully');
}}
/>
</div>
);
}
Multiple Import Options
import { BackupImport } from 'bigblocks';
export function ImportOptions() {
return (
<div className="space-y-6">
<div>
<h3 className="font-semibold mb-2">Import from File</h3>
<BackupImport
onImport={handleFileImport}
onImportSuccess={() => {
console.log('File import complete');
}}
/>
</div>
<div className="divider">OR</div>
<div>
<h3 className="font-semibold mb-2">Import from Cloud</h3>
<button onClick={handleCloudImport}>
Import from Google Drive
</button>
</div>
</div>
);
}
File Handling
The component accepts various backup file formats:
async function handleImport(file: File) {
const content = await file.text();
// Detect format
if (content.startsWith('U2FsdGVkX1')) {
// Encrypted backup
const password = await promptForPassword();
const decrypted = decrypt(content, password);
await restoreFromBackup(decrypted);
} else if (content.startsWith('{')) {
// JSON backup
const backup = JSON.parse(content);
await restoreFromBackup(backup);
} else if (content.match(/^[KL5][1-9A-HJ-NP-Za-km-z]{50,51}$/)) {
// WIF format
await restoreFromWIF(content);
} else {
throw new Error('Unknown backup format');
}
}
Styling
The component uses Radix Themes and can be customized:
/* Default structure */
.backup-import-container {
/* Button styling from Radix */
}
.backup-import-input {
/* Hidden file input */
display: none;
}
Best Practices
- Validation: Always validate file format and size before processing
- Error Handling: Provide clear error messages for common issues
- Progress Feedback: Show loading state during import
- Success Confirmation: Always confirm successful import
- Security: Never log or expose sensitive backup data
Security Considerations
- Client-Side Processing: Handle backup data only in the browser
- File Validation: Check file size and format before processing
- Password Protection: Prompt for passwords for encrypted backups
- Memory Cleanup: Clear sensitive data from memory after use
- Error Messages: Don't expose sensitive information in errors
Troubleshooting
Import Button Not Working
- Check that onImport handler is properly defined
- Ensure component isn't disabled
- Verify file input isn't blocked by browser
File Not Processing
- Check file format is supported
- Verify file isn't corrupted
- Ensure async operations are properly handled
Success Callback Not Firing
- Make sure onImport doesn't throw errors
- Verify onImportSuccess prop is passed
- Check that import process completes successfully
Related Components
- BackupDownload - Download backups
- FileImport - Generic file import
- IdentityGeneration - Create new identity
- LoginForm - Sign in with existing backup
API Reference
File Processing
The onImport handler receives a File object:
interface File {
name: string;
size: number;
type: string;
lastModified: number;
text(): Promise<string>;
arrayBuffer(): Promise<ArrayBuffer>;
}
Error Handling
Errors thrown in onImport will be caught and displayed by the component. Return or throw errors to show them to users.
Notes for Improvement
Major Simplification: The actual component is much simpler than the prompt described. It lacks:
- Multiple format support options
- Built-in validation
- Progress tracking
- Format detection
- The extensive backend API integration described
- Drag and drop functionality
- Conflict resolution
- Preview capabilities
The actual implementation is a basic file input button that delegates all processing to the onImport handler.