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>
This commit is contained in:
parent
093846b351
commit
4a3d2012be
6 changed files with 69 additions and 18 deletions
|
|
@ -48,6 +48,7 @@ export abstract class BaseService {
|
|||
protected storageService: any = null
|
||||
protected toastService: any = null
|
||||
protected invoiceService: any = null
|
||||
protected lnbitsAPI: any = null
|
||||
|
||||
// Service state
|
||||
public readonly isInitialized: Ref<boolean> = ref(false)
|
||||
|
|
@ -140,6 +141,7 @@ export abstract class BaseService {
|
|||
this.storageService = tryInjectService(SERVICE_TOKENS.STORAGE_SERVICE)
|
||||
this.toastService = tryInjectService(SERVICE_TOKENS.TOAST_SERVICE)
|
||||
this.invoiceService = tryInjectService(SERVICE_TOKENS.INVOICE_SERVICE)
|
||||
this.lnbitsAPI = tryInjectService(SERVICE_TOKENS.LNBITS_API)
|
||||
|
||||
// Check if all required dependencies are available
|
||||
const missingDeps = this.getMissingDependencies()
|
||||
|
|
@ -193,6 +195,9 @@ export abstract class BaseService {
|
|||
if (deps.includes('ToastService') && !this.toastService) {
|
||||
missing.push('ToastService')
|
||||
}
|
||||
if (deps.includes('LnbitsAPI') && !this.lnbitsAPI) {
|
||||
missing.push('LnbitsAPI')
|
||||
}
|
||||
|
||||
return missing
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,9 @@ export const SERVICE_TOKENS = {
|
|||
|
||||
// Nostrmarket services
|
||||
NOSTRMARKET_SERVICE: Symbol('nostrmarketService'),
|
||||
|
||||
// API services
|
||||
LNBITS_API: Symbol('lnbitsAPI'),
|
||||
} as const
|
||||
|
||||
// Type-safe injection helpers
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Event, Ticket } from '../types/event'
|
||||
import { config } from '@/lib/config'
|
||||
import { lnbitsAPI } from './lnbits'
|
||||
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
||||
import type { LnbitsAPI } from './lnbits'
|
||||
|
||||
const API_BASE_URL = config.api.baseUrl || 'http://lnbits'
|
||||
const API_KEY = config.api.key
|
||||
|
|
@ -39,6 +40,9 @@ export async function fetchEvents(): Promise<Event[]> {
|
|||
|
||||
export async function purchaseTicket(eventId: string): Promise<{ payment_hash: string; payment_request: string }> {
|
||||
try {
|
||||
// Get injected LnbitsAPI service
|
||||
const lnbitsAPI = injectService(SERVICE_TOKENS.LNBITS_API) as LnbitsAPI
|
||||
|
||||
// Get current user to ensure authentication
|
||||
const user = await lnbitsAPI.getCurrentUser()
|
||||
if (!user) {
|
||||
|
|
@ -135,6 +139,9 @@ export async function checkPaymentStatus(eventId: string, paymentHash: string):
|
|||
|
||||
export async function fetchUserTickets(userId: string): Promise<Ticket[]> {
|
||||
try {
|
||||
// Get injected LnbitsAPI service
|
||||
const lnbitsAPI = injectService(SERVICE_TOKENS.LNBITS_API) as LnbitsAPI
|
||||
|
||||
const response = await fetch(
|
||||
`${API_BASE_URL}/events/api/v1/tickets/user/${userId}`,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -61,16 +61,33 @@ interface User {
|
|||
}
|
||||
}
|
||||
|
||||
import { BaseService } from '@/core/base/BaseService'
|
||||
import { getApiUrl, getAuthToken, setAuthToken, removeAuthToken } from '@/lib/config/lnbits'
|
||||
|
||||
class LnbitsAPI {
|
||||
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 = {}
|
||||
|
|
@ -183,5 +200,5 @@ class LnbitsAPI {
|
|||
}
|
||||
}
|
||||
|
||||
export const lnbitsAPI = new LnbitsAPI()
|
||||
// Service is now registered in the DI container
|
||||
export type { LoginCredentials, RegisterData, AuthResponse, User }
|
||||
|
|
@ -2,14 +2,14 @@
|
|||
import { ref, computed } from 'vue'
|
||||
import { BaseService } from '@/core/base/BaseService'
|
||||
import { eventBus } from '@/core/event-bus'
|
||||
import { lnbitsAPI, type LoginCredentials, type RegisterData, type User } from '@/lib/api/lnbits'
|
||||
import type { LoginCredentials, RegisterData, User } from '@/lib/api/lnbits'
|
||||
|
||||
export class AuthService extends BaseService {
|
||||
// Service metadata
|
||||
protected readonly metadata = {
|
||||
name: 'AuthService',
|
||||
version: '1.0.0',
|
||||
dependencies: [] // Auth service has no dependencies on other services
|
||||
dependencies: ['LnbitsAPI'] // Auth service depends on LnbitsAPI for authentication
|
||||
}
|
||||
|
||||
// Public state
|
||||
|
|
@ -47,7 +47,7 @@ export class AuthService extends BaseService {
|
|||
}
|
||||
|
||||
async checkAuth(): Promise<boolean> {
|
||||
if (!lnbitsAPI.isAuthenticated()) {
|
||||
if (!this.lnbitsAPI.isAuthenticated()) {
|
||||
this.debug('No auth token found - user needs to login')
|
||||
this.isAuthenticated.value = false
|
||||
this.user.value = null
|
||||
|
|
@ -56,7 +56,7 @@ export class AuthService extends BaseService {
|
|||
|
||||
try {
|
||||
this.isLoading.value = true
|
||||
const userData = await lnbitsAPI.getCurrentUser()
|
||||
const userData = await this.lnbitsAPI.getCurrentUser()
|
||||
|
||||
this.user.value = userData
|
||||
this.isAuthenticated.value = true
|
||||
|
|
@ -70,7 +70,7 @@ export class AuthService extends BaseService {
|
|||
this.isAuthenticated.value = false
|
||||
this.user.value = null
|
||||
// Clear invalid token
|
||||
lnbitsAPI.logout()
|
||||
this.lnbitsAPI.logout()
|
||||
return false
|
||||
} finally {
|
||||
this.isLoading.value = false
|
||||
|
|
@ -81,8 +81,8 @@ export class AuthService extends BaseService {
|
|||
this.isLoading.value = true
|
||||
|
||||
try {
|
||||
await lnbitsAPI.login(credentials)
|
||||
const userData = await lnbitsAPI.getCurrentUser()
|
||||
await this.lnbitsAPI.login(credentials)
|
||||
const userData = await this.lnbitsAPI.getCurrentUser()
|
||||
|
||||
this.user.value = userData
|
||||
this.isAuthenticated.value = true
|
||||
|
|
@ -102,8 +102,8 @@ export class AuthService extends BaseService {
|
|||
this.isLoading.value = true
|
||||
|
||||
try {
|
||||
await lnbitsAPI.register(data)
|
||||
const userData = await lnbitsAPI.getCurrentUser()
|
||||
await this.lnbitsAPI.register(data)
|
||||
const userData = await this.lnbitsAPI.getCurrentUser()
|
||||
|
||||
this.user.value = userData
|
||||
this.isAuthenticated.value = true
|
||||
|
|
@ -120,7 +120,7 @@ export class AuthService extends BaseService {
|
|||
}
|
||||
|
||||
async logout(): Promise<void> {
|
||||
lnbitsAPI.logout()
|
||||
this.lnbitsAPI.logout()
|
||||
this.user.value = null
|
||||
this.isAuthenticated.value = false
|
||||
this.error.value = null
|
||||
|
|
@ -134,14 +134,14 @@ export class AuthService extends BaseService {
|
|||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
// Alias for checkAuth for compatibility
|
||||
await this.checkAuth()
|
||||
// Call BaseService initialize first to inject dependencies
|
||||
await super.initialize()
|
||||
}
|
||||
|
||||
async updatePassword(currentPassword: string, newPassword: string): Promise<void> {
|
||||
try {
|
||||
this.isLoading.value = true
|
||||
const updatedUser = await lnbitsAPI.updatePassword(currentPassword, newPassword)
|
||||
const updatedUser = await this.lnbitsAPI.updatePassword(currentPassword, newPassword)
|
||||
this.user.value = updatedUser
|
||||
} catch (error) {
|
||||
const err = this.handleError(error, 'updatePassword')
|
||||
|
|
@ -154,7 +154,7 @@ export class AuthService extends BaseService {
|
|||
async updateProfile(data: Partial<User>): Promise<void> {
|
||||
try {
|
||||
this.isLoading.value = true
|
||||
const updatedUser = await lnbitsAPI.updateProfile(data)
|
||||
const updatedUser = await this.lnbitsAPI.updateProfile(data)
|
||||
this.user.value = updatedUser
|
||||
} catch (error) {
|
||||
const err = this.handleError(error, 'updateProfile')
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ import { visibilityService } from '@/core/services/VisibilityService'
|
|||
import { storageService } from '@/core/services/StorageService'
|
||||
import { toastService } from '@/core/services/ToastService'
|
||||
import { InvoiceService } from '@/core/services/invoiceService'
|
||||
import { LnbitsAPI } from '@/lib/api/lnbits'
|
||||
|
||||
// Create service instances
|
||||
const invoiceService = new InvoiceService()
|
||||
const lnbitsAPI = new LnbitsAPI()
|
||||
|
||||
/**
|
||||
* Base Module Plugin
|
||||
|
|
@ -51,12 +53,22 @@ export const baseModule: ModulePlugin = {
|
|||
// Register invoice service
|
||||
container.provide(SERVICE_TOKENS.INVOICE_SERVICE, invoiceService)
|
||||
|
||||
// Register API services
|
||||
container.provide(SERVICE_TOKENS.LNBITS_API, lnbitsAPI)
|
||||
|
||||
// Register PWA service
|
||||
container.provide('pwaService', pwaService)
|
||||
|
||||
// Initialize core services
|
||||
// Initialize core services in dependency order
|
||||
relayHub.setRelayUrls(options?.config?.nostr?.relays || [])
|
||||
await relayHub.initialize()
|
||||
|
||||
// Initialize LnbitsAPI first since AuthService depends on it
|
||||
await lnbitsAPI.initialize({
|
||||
waitForDependencies: false, // LnbitsAPI is core infrastructure with no dependencies
|
||||
maxRetries: 1
|
||||
})
|
||||
|
||||
// Auth initialization moved to app.ts before router guards
|
||||
await paymentService.initialize({
|
||||
waitForDependencies: true, // PaymentService depends on AuthService
|
||||
|
|
@ -74,6 +86,7 @@ export const baseModule: ModulePlugin = {
|
|||
waitForDependencies: false, // ToastService has no dependencies
|
||||
maxRetries: 1
|
||||
})
|
||||
// InvoiceService doesn't need initialization as it's not a BaseService
|
||||
|
||||
console.log('✅ Base module installed successfully')
|
||||
},
|
||||
|
|
@ -88,6 +101,12 @@ export const baseModule: ModulePlugin = {
|
|||
await visibilityService.dispose()
|
||||
await storageService.dispose()
|
||||
await toastService.dispose()
|
||||
// InvoiceService doesn't need disposal as it's not a BaseService
|
||||
await lnbitsAPI.dispose()
|
||||
|
||||
// Remove services from DI container
|
||||
container.remove(SERVICE_TOKENS.LNBITS_API)
|
||||
container.remove(SERVICE_TOKENS.INVOICE_SERVICE)
|
||||
|
||||
console.log('✅ Base module uninstalled')
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue