web-app/src/lib/api/lnbits.ts
padreug 4a3d2012be Complete LnbitsAPI migration to dependency injection pattern
- Convert LnbitsAPI from singleton to BaseService extension
- Add LNBITS_API service token to DI container
- Register LnbitsAPI service in base module with proper initialization order
- Update AuthService to depend on injected LnbitsAPI instead of singleton
- Fix BaseService to properly track LnbitsAPI dependency in getMissingDependencies
- Update events API functions to use dependency injection
- Resolve initialization timing issue preventing application startup

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-07 01:58:36 +02:00

204 lines
No EOL
4.8 KiB
TypeScript

interface LoginCredentials {
username: string
password: string
}
interface RegisterData {
username: string
email?: string
password: string
password_repeat: string
}
interface AuthResponse {
access_token: string
user_id: string
username?: string
email?: string
}
interface Wallet {
id: string
user: string
name: string
adminkey: string
inkey: string
deleted: boolean
created_at: string
updated_at: string
currency?: string
balance_msat: number
extra?: {
icon: string
color: string
pinned: boolean
}
}
interface User {
id: string
username?: string
email?: string
pubkey?: string
prvkey?: string // Nostr private key for user
external_id?: string
extensions: string[]
wallets: Wallet[]
admin: boolean
super_user: boolean
fiat_providers: string[]
has_password: boolean
created_at: string
updated_at: string
extra?: {
email_verified?: boolean
first_name?: string
last_name?: string
display_name?: string
picture?: string
provider?: string
visible_wallet_count?: number
}
}
import { BaseService } from '@/core/base/BaseService'
import { getApiUrl, getAuthToken, setAuthToken, removeAuthToken } from '@/lib/config/lnbits'
export class LnbitsAPI extends BaseService {
// Service metadata
protected readonly metadata = {
name: 'LnbitsAPI',
version: '1.0.0',
dependencies: [] // No dependencies - this is a core infrastructure service
}
private accessToken: string | null = null
constructor() {
super()
// Try to load token from localStorage
this.accessToken = getAuthToken()
}
/**
* Service-specific initialization (called by BaseService)
*/
protected async onInitialize(): Promise<void> {
this.debug('LnbitsAPI initialized')
// Service is ready to use
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = getApiUrl(endpoint)
console.log('🔧 LNBits API request:', { endpoint, fullUrl: url })
const headers: HeadersInit = {
'Content-Type': 'application/json',
...options.headers,
}
if (this.accessToken) {
(headers as Record<string, string>)['Authorization'] = `Bearer ${this.accessToken}`
}
const response = await fetch(url, {
...options,
headers,
})
if (!response.ok) {
const errorText = await response.text()
console.error('LNBits API Error:', {
status: response.status,
statusText: response.statusText,
errorText
})
throw new Error(`API request failed: ${response.status} ${response.statusText}`)
}
const data = await response.json()
return data
}
async login(credentials: LoginCredentials): Promise<AuthResponse> {
const response = await this.request<AuthResponse>('/auth', {
method: 'POST',
body: JSON.stringify(credentials),
})
this.accessToken = response.access_token
setAuthToken(response.access_token)
return response
}
async register(data: RegisterData): Promise<AuthResponse> {
const response = await this.request<AuthResponse>('/auth/register', {
method: 'POST',
body: JSON.stringify(data),
})
this.accessToken = response.access_token
setAuthToken(response.access_token)
return response
}
async logout(): Promise<void> {
// Just clear local state - no API call needed for logout
this.accessToken = null
removeAuthToken()
}
async getCurrentUser(): Promise<User> {
// First get basic user info from /auth
const basicUser = await this.request<User>('/auth')
// Then get Nostr keys from /auth/nostr/me (this was working in main branch)
try {
const nostrUser = await this.request<User>('/auth/nostr/me')
// Merge the data - basic user info + Nostr keys
return {
...basicUser,
pubkey: nostrUser.pubkey,
prvkey: nostrUser.prvkey
}
} catch (error) {
console.warn('Failed to fetch Nostr keys, returning basic user info:', error)
// Return basic user info without Nostr keys if the endpoint fails
return basicUser
}
}
async updatePassword(currentPassword: string, newPassword: string): Promise<User> {
return this.request<User>('/auth/password', {
method: 'PUT',
body: JSON.stringify({
current_password: currentPassword,
new_password: newPassword,
}),
})
}
async updateProfile(data: Partial<User>): Promise<User> {
return this.request<User>('/auth/update', {
method: 'PUT',
body: JSON.stringify(data),
})
}
isAuthenticated(): boolean {
return !!this.accessToken
}
getAccessToken(): string | null {
return this.accessToken
}
}
// Service is now registered in the DI container
export type { LoginCredentials, RegisterData, AuthResponse, User }