Refactor AuthService and market components for improved functionality and error handling
- Integrate LNbits API for authentication in AuthService, replacing token management with direct API calls for user data. - Enhance login and registration processes to utilize the new API, improving user experience and error handling. - Update market components to include detailed logging and fallback mechanisms for offline scenarios, ensuring better resilience during market data loading. - Refactor market preloader to handle connection timeouts and provide sample data as a fallback, enhancing user experience in offline mode.
This commit is contained in:
parent
daa9656680
commit
55e99e002d
5 changed files with 178 additions and 63 deletions
|
|
@ -1,8 +1,7 @@
|
|||
// Auth service for LNbits integration
|
||||
import { ref } from 'vue'
|
||||
import { eventBus } from '@/core/event-bus'
|
||||
import { getAuthToken } from '@/lib/config/lnbits'
|
||||
import { config } from '@/lib/config'
|
||||
import { lnbitsAPI, type LoginCredentials, type RegisterData } from '@/lib/api/lnbits'
|
||||
|
||||
export class AuthService {
|
||||
public isAuthenticated = ref(false)
|
||||
|
|
@ -21,39 +20,16 @@ export class AuthService {
|
|||
}
|
||||
|
||||
async checkAuth(): Promise<boolean> {
|
||||
const authToken = getAuthToken()
|
||||
|
||||
if (!authToken) {
|
||||
if (!lnbitsAPI.isAuthenticated()) {
|
||||
console.log('🔑 No auth token found - user needs to login')
|
||||
this.isAuthenticated.value = false
|
||||
this.user.value = null
|
||||
return false
|
||||
}
|
||||
|
||||
// Fetch current user data from API
|
||||
try {
|
||||
this.isLoading.value = true
|
||||
const API_BASE_URL = config.api.baseUrl || 'http://localhost:5006'
|
||||
const response = await fetch(`${API_BASE_URL}/api/v1/auth/nostr/me`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${authToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
console.log('🔑 Auth token invalid - user needs to login')
|
||||
this.logout()
|
||||
return false
|
||||
}
|
||||
console.warn(`🔑 Failed to fetch user data: ${response.status} - authentication may not be properly configured`)
|
||||
this.isAuthenticated.value = false
|
||||
this.user.value = null
|
||||
return false
|
||||
}
|
||||
|
||||
const userData = await response.json()
|
||||
const userData = await lnbitsAPI.getCurrentUser()
|
||||
|
||||
this.user.value = userData
|
||||
this.isAuthenticated.value = true
|
||||
|
|
@ -66,25 +42,25 @@ export class AuthService {
|
|||
console.warn('🔑 Authentication check failed:', error)
|
||||
this.isAuthenticated.value = false
|
||||
this.user.value = null
|
||||
// Clear invalid token
|
||||
lnbitsAPI.logout()
|
||||
return false
|
||||
} finally {
|
||||
this.isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async login(credentials: any): Promise<void> {
|
||||
async login(credentials: LoginCredentials): Promise<void> {
|
||||
this.isLoading.value = true
|
||||
|
||||
try {
|
||||
// Implement your login logic here
|
||||
// For demo purposes, we'll accept any credentials
|
||||
this.user.value = credentials
|
||||
await lnbitsAPI.login(credentials)
|
||||
const userData = await lnbitsAPI.getCurrentUser()
|
||||
|
||||
this.user.value = userData
|
||||
this.isAuthenticated.value = true
|
||||
|
||||
// Store auth state
|
||||
localStorage.setItem('auth', JSON.stringify(credentials))
|
||||
|
||||
eventBus.emit('auth:login', { user: credentials }, 'auth-service')
|
||||
eventBus.emit('auth:login', { user: userData }, 'auth-service')
|
||||
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error)
|
||||
|
|
@ -95,10 +71,31 @@ export class AuthService {
|
|||
}
|
||||
}
|
||||
|
||||
async register(data: RegisterData): Promise<void> {
|
||||
this.isLoading.value = true
|
||||
|
||||
try {
|
||||
await lnbitsAPI.register(data)
|
||||
const userData = await lnbitsAPI.getCurrentUser()
|
||||
|
||||
this.user.value = userData
|
||||
this.isAuthenticated.value = true
|
||||
|
||||
eventBus.emit('auth:login', { user: userData }, 'auth-service')
|
||||
|
||||
} catch (error) {
|
||||
console.error('Registration failed:', error)
|
||||
eventBus.emit('auth:login-failed', { error }, 'auth-service')
|
||||
throw error
|
||||
} finally {
|
||||
this.isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
lnbitsAPI.logout()
|
||||
this.user.value = null
|
||||
this.isAuthenticated.value = false
|
||||
localStorage.removeItem('auth')
|
||||
|
||||
eventBus.emit('auth:logout', {}, 'auth-service')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,16 +404,29 @@ export class ChatService {
|
|||
console.log('Loading message history for', peerPubkeys.length, 'peers')
|
||||
|
||||
// Query historical messages (kind 4) to/from known peers
|
||||
const events = await relayHub.queryEvents([
|
||||
// We need separate queries for sent vs received messages due to different tagging
|
||||
const receivedEvents = await relayHub.queryEvents([
|
||||
{
|
||||
kinds: [4],
|
||||
authors: [userPubkey, ...peerPubkeys], // Messages from us or peers
|
||||
'#p': [userPubkey], // Messages tagged with our pubkey
|
||||
limit: 100 // Limit to last 100 messages per conversation
|
||||
authors: peerPubkeys, // Messages from peers
|
||||
'#p': [userPubkey], // Messages tagged to us
|
||||
limit: 100
|
||||
}
|
||||
])
|
||||
|
||||
console.log('Found', events.length, 'historical messages')
|
||||
const sentEvents = await relayHub.queryEvents([
|
||||
{
|
||||
kinds: [4],
|
||||
authors: [userPubkey], // Messages from us
|
||||
'#p': peerPubkeys, // Messages tagged to peers
|
||||
limit: 100
|
||||
}
|
||||
])
|
||||
|
||||
const events = [...receivedEvents, ...sentEvents]
|
||||
.sort((a, b) => a.created_at - b.created_at) // Sort by timestamp
|
||||
|
||||
console.log('Found', events.length, 'historical messages:', receivedEvents.length, 'received,', sentEvents.length, 'sent')
|
||||
|
||||
// Process historical messages
|
||||
for (const event of events) {
|
||||
|
|
|
|||
|
|
@ -70,8 +70,31 @@ export function useMarket() {
|
|||
// Load market data from Nostr events
|
||||
const loadMarketData = async (marketData: any) => {
|
||||
try {
|
||||
// Load market data from Nostr events
|
||||
console.log('🛒 Loading market data for:', { identifier: marketData.identifier, pubkey: marketData.pubkey?.slice(0, 8) })
|
||||
|
||||
// Check if we can query events (relays are connected)
|
||||
if (!isConnected.value) {
|
||||
console.log('🛒 Not connected to relays, creating default market')
|
||||
// Create default market without trying to fetch from Nostr
|
||||
const market = {
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.nostr.relays,
|
||||
selected: true,
|
||||
opts: {
|
||||
name: 'Demo Market (Offline)',
|
||||
description: 'Demo market running in offline mode',
|
||||
merchants: [],
|
||||
ui: {}
|
||||
}
|
||||
}
|
||||
|
||||
marketStore.addMarket(market)
|
||||
marketStore.setActiveMarket(market)
|
||||
return
|
||||
}
|
||||
|
||||
// Load market data from Nostr events
|
||||
// Fetch market configuration event
|
||||
const events = await relayHub.queryEvents([
|
||||
{
|
||||
|
|
@ -81,6 +104,8 @@ export function useMarket() {
|
|||
}
|
||||
])
|
||||
|
||||
console.log('🛒 Found', events.length, 'market events')
|
||||
|
||||
// Process market events
|
||||
|
||||
if (events.length > 0) {
|
||||
|
|
@ -90,7 +115,7 @@ export function useMarket() {
|
|||
const market = {
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.market.supportedRelays,
|
||||
relays: config.nostr.relays,
|
||||
selected: true,
|
||||
opts: JSON.parse(marketEvent.content)
|
||||
}
|
||||
|
|
@ -103,7 +128,7 @@ export function useMarket() {
|
|||
const market = {
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.market.supportedRelays,
|
||||
relays: config.nostr.relays,
|
||||
selected: true,
|
||||
opts: {
|
||||
name: 'Ariège Market',
|
||||
|
|
@ -122,7 +147,7 @@ export function useMarket() {
|
|||
const market = {
|
||||
d: marketData.identifier,
|
||||
pubkey: marketData.pubkey,
|
||||
relays: config.market.supportedRelays,
|
||||
relays: config.nostr.relays,
|
||||
selected: true,
|
||||
opts: {
|
||||
name: 'Default Market',
|
||||
|
|
@ -160,6 +185,8 @@ export function useMarket() {
|
|||
}
|
||||
])
|
||||
|
||||
console.log('🛒 Found', events.length, 'stall events for', merchants.length, 'merchants')
|
||||
|
||||
// Process stall events
|
||||
|
||||
// Group events by stall ID and keep only the most recent version
|
||||
|
|
@ -222,6 +249,8 @@ export function useMarket() {
|
|||
}
|
||||
])
|
||||
|
||||
console.log('🛒 Found', events.length, 'product events for', merchants.length, 'merchants')
|
||||
|
||||
// Process product events
|
||||
|
||||
// Group events by product ID and keep only the most recent version
|
||||
|
|
@ -463,35 +492,46 @@ export function useMarket() {
|
|||
// Connect to market
|
||||
const connectToMarket = async () => {
|
||||
try {
|
||||
console.log('🛒 Checking RelayHub connection...')
|
||||
// Use existing relay hub connection (should already be connected by base module)
|
||||
isConnected.value = relayHub.isConnected.value
|
||||
console.log('🛒 RelayHub connected:', isConnected.value)
|
||||
|
||||
if (!isConnected.value) {
|
||||
console.warn('RelayHub not connected, attempting to connect...')
|
||||
await relayHub.connect()
|
||||
isConnected.value = relayHub.isConnected.value
|
||||
|
||||
if (!isConnected.value) {
|
||||
throw new Error('Failed to connect to Nostr relays')
|
||||
}
|
||||
console.warn('🛒 RelayHub not connected - this is expected if authentication is not complete')
|
||||
// Don't try to connect here - let the base module handle connections
|
||||
// Just proceed with offline/demo mode
|
||||
console.log('🛒 Proceeding in offline mode')
|
||||
}
|
||||
|
||||
// Market connected successfully
|
||||
console.log('🛒 Market connected successfully')
|
||||
|
||||
// Load market data
|
||||
console.log('🛒 Loading basic market data...')
|
||||
await loadMarketData({
|
||||
identifier: 'default',
|
||||
pubkey: nostrStore.account?.pubkey || ''
|
||||
})
|
||||
|
||||
// Load stalls and products
|
||||
await loadStalls()
|
||||
await loadProducts()
|
||||
// Load stalls and products only if connected
|
||||
if (isConnected.value) {
|
||||
console.log('🛒 Loading stalls...')
|
||||
await loadStalls()
|
||||
console.log('🛒 Loading products...')
|
||||
await loadProducts()
|
||||
} else {
|
||||
console.log('🛒 Skipping stalls/products loading - not connected to relays')
|
||||
// Add sample products for demo mode
|
||||
console.log('🛒 Adding sample products for offline demo...')
|
||||
addSampleProducts()
|
||||
}
|
||||
|
||||
// Subscribe to updates
|
||||
console.log('🛒 Subscribing to market updates...')
|
||||
subscribeToMarketUpdates()
|
||||
|
||||
} catch (err) {
|
||||
console.error('🛒 Failed to connect to market:', err)
|
||||
error.value = err instanceof Error ? err : new Error('Failed to connect to market')
|
||||
throw err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,32 +14,97 @@ export function useMarketPreloader() {
|
|||
const preloadMarket = async () => {
|
||||
// Don't preload if already done or currently preloading
|
||||
if (isPreloaded.value || isPreloading.value) {
|
||||
console.log('🛒 Market preload skipped - already loaded or in progress')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('🛒 Starting market preload...')
|
||||
|
||||
try {
|
||||
isPreloading.value = true
|
||||
preloadError.value = null
|
||||
|
||||
const naddr = config.market.defaultNaddr
|
||||
if (!naddr) {
|
||||
console.warn('🛒 No market naddr configured, skipping preload')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('🛒 Using market naddr:', naddr.slice(0, 20) + '...')
|
||||
|
||||
// Add timeout protection to prevent hanging
|
||||
const timeoutMs = 30000 // 30 seconds
|
||||
|
||||
const connectWithTimeout = async () => {
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Market connection timeout after 30 seconds')), timeoutMs)
|
||||
})
|
||||
|
||||
return Promise.race([
|
||||
market.connectToMarket(),
|
||||
timeoutPromise
|
||||
])
|
||||
}
|
||||
|
||||
const loadWithTimeout = async () => {
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Market loading timeout after 30 seconds')), timeoutMs)
|
||||
})
|
||||
|
||||
return Promise.race([
|
||||
market.loadMarket(naddr),
|
||||
timeoutPromise
|
||||
])
|
||||
}
|
||||
|
||||
// Connect to market
|
||||
await market.connectToMarket()
|
||||
console.log('🛒 Connecting to market...')
|
||||
await connectWithTimeout()
|
||||
|
||||
// Load market data
|
||||
await market.loadMarket(naddr)
|
||||
console.log('🛒 Loading market data...')
|
||||
await loadWithTimeout()
|
||||
|
||||
// Clear any error state since preloading succeeded
|
||||
marketStore.setError(null)
|
||||
|
||||
isPreloaded.value = true
|
||||
console.log('🛒 Market preload completed successfully')
|
||||
|
||||
} catch (error) {
|
||||
preloadError.value = error instanceof Error ? error.message : 'Failed to preload market'
|
||||
// Don't throw error, let the UI handle it gracefully
|
||||
console.error('🛒 Market preload failed:', error)
|
||||
console.log('🛒 Attempting fallback with sample data...')
|
||||
|
||||
try {
|
||||
// Create a basic market with sample data as fallback
|
||||
const fallbackMarket = {
|
||||
d: 'demo-market',
|
||||
pubkey: 'demo',
|
||||
relays: ['ws://localhost:5006/nostrrelay/test1'],
|
||||
selected: true,
|
||||
opts: {
|
||||
name: 'Demo Market',
|
||||
description: 'Demo market with sample products',
|
||||
merchants: [],
|
||||
ui: {}
|
||||
}
|
||||
}
|
||||
|
||||
marketStore.addMarket(fallbackMarket)
|
||||
marketStore.setActiveMarket(fallbackMarket)
|
||||
|
||||
// Add some sample products if the useMarket composable supports it
|
||||
if (market.addSampleProducts && typeof market.addSampleProducts === 'function') {
|
||||
market.addSampleProducts()
|
||||
}
|
||||
|
||||
isPreloaded.value = true
|
||||
console.log('🛒 Market preload completed with fallback data')
|
||||
|
||||
} catch (fallbackError) {
|
||||
console.error('🛒 Fallback also failed:', fallbackError)
|
||||
preloadError.value = error instanceof Error ? error.message : 'Failed to preload market'
|
||||
}
|
||||
} finally {
|
||||
isPreloading.value = false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue