- 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>
204 lines
No EOL
4.8 KiB
TypeScript
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 }
|