Release v1.0.9 - Add wallet tab with Cashu and Lightning support

- Add wallet tab with NWC (Nostr Wallet Connect) Lightning support
- Add Cashu ecash wallet with mint management, send/receive tokens
- Add Cashu deposit feature (mint via Lightning invoice)
- Add token viewer showing proof amounts and timestamps
- Add refresh button with auto-refresh for spent proof detection
- Add browser sync warning for Cashu users on welcome screen
- Add Cashu onboarding info panel with storage considerations
- Add settings page sync info note explaining how to change sync
- Add backups page for vault snapshot management
- Add About section to identity (You) page
- Fix lint accessibility issues in wallet component

Files modified:
- projects/common/src/lib/services/nwc/* (new)
- projects/common/src/lib/services/cashu/* (new)
- projects/common/src/lib/services/storage/* (extended)
- projects/chrome/src/app/components/home/wallet/*
- projects/firefox/src/app/components/home/wallet/*
- projects/chrome/src/app/components/welcome/*
- projects/firefox/src/app/components/welcome/*
- projects/chrome/src/app/components/home/settings/*
- projects/firefox/src/app/components/home/settings/*
- projects/chrome/src/app/components/home/identity/*
- projects/firefox/src/app/components/home/identity/*
- projects/chrome/src/app/components/home/backups/* (new)
- projects/firefox/src/app/components/home/backups/* (new)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
woikos
2025-12-21 15:40:25 +01:00
parent 1f8d478cd7
commit ebc96e7201
54 changed files with 9542 additions and 50 deletions

View File

@@ -0,0 +1,126 @@
import { Component, inject, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import {
ConfirmComponent,
LoggerService,
SignerMetaData_VaultSnapshot,
StartupService,
StorageService,
} from '@common';
import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage-service-config';
@Component({
selector: 'app-backups',
templateUrl: './backups.component.html',
styleUrl: './backups.component.scss',
imports: [ConfirmComponent],
})
export class BackupsComponent implements OnInit {
readonly #router = inject(Router);
readonly #storage = inject(StorageService);
readonly #startup = inject(StartupService);
readonly #logger = inject(LoggerService);
backups: SignerMetaData_VaultSnapshot[] = [];
maxBackups = 5;
restoringBackupId: string | null = null;
ngOnInit(): void {
this.loadBackups();
this.maxBackups = this.#storage.getSignerMetaHandler().getMaxBackups();
}
loadBackups(): void {
this.backups = this.#storage.getSignerMetaHandler().getBackups();
}
async onMaxBackupsChange(event: Event): Promise<void> {
const input = event.target as HTMLInputElement;
const value = parseInt(input.value, 10);
if (!isNaN(value) && value >= 1 && value <= 20) {
this.maxBackups = value;
await this.#storage.getSignerMetaHandler().setMaxBackups(value);
}
}
async createManualBackup(): Promise<void> {
const browserSyncData = this.#storage.getBrowserSyncHandler().browserSyncData;
if (browserSyncData) {
await this.#storage.getSignerMetaHandler().createBackup(browserSyncData, 'manual');
this.loadBackups();
}
}
async restoreBackup(backupId: string): Promise<void> {
this.restoringBackupId = backupId;
try {
// First, create a pre-restore backup of current state
const currentData = this.#storage.getBrowserSyncHandler().browserSyncData;
if (currentData) {
await this.#storage.getSignerMetaHandler().createBackup(currentData, 'pre-restore');
}
// Get the backup data
const backupData = this.#storage.getSignerMetaHandler().getBackupData(backupId);
if (!backupData) {
throw new Error('Backup not found');
}
// Import the backup
await this.#storage.deleteVault(true);
await this.#storage.importVault(backupData);
this.#logger.logVaultImport('Backup Restore');
this.#storage.isInitialized = false;
this.#startup.startOver(getNewStorageServiceConfig());
} catch (error) {
console.error('Failed to restore backup:', error);
this.restoringBackupId = null;
}
}
async deleteBackup(backupId: string): Promise<void> {
await this.#storage.getSignerMetaHandler().deleteBackup(backupId);
this.loadBackups();
}
formatDate(isoDate: string): string {
const date = new Date(isoDate);
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
}
getReasonLabel(reason?: string): string {
switch (reason) {
case 'auto':
return 'Auto';
case 'manual':
return 'Manual';
case 'pre-restore':
return 'Pre-Restore';
default:
return 'Unknown';
}
}
getReasonClass(reason?: string): string {
switch (reason) {
case 'auto':
return 'reason-auto';
case 'manual':
return 'reason-manual';
case 'pre-restore':
return 'reason-prerestore';
default:
return '';
}
}
goBack(): void {
this.#router.navigateByUrl('/home/settings');
}
async onClickLock(): Promise<void> {
this.#logger.logVaultLock();
await this.#storage.lockVault();
this.#router.navigateByUrl('/vault-login');
}
}