forked from jsnbuchanan/crowd-funder-for-time-pwa
fix(ProfileService): revert to working endpoint for profile loading
- Revert ProfileService from broken /api/partner/userProfile endpoint to working /api/partner/userProfileForIssuer/${did}
- Fix location data display by restoring single profile object response parsing
- Remove complex array handling logic that was unnecessary for current user profiles
- Restore original working functionality that was broken by recent refactoring
Problem: Recent ProfileService creation changed endpoint from working userProfileForIssuer/${did}
to broken userProfile (list endpoint), causing location data to not display properly.
Solution: Revert to original working endpoint and response parsing logic that returns
single profile objects with location data instead of arrays of all profiles.
Files changed:
- src/services/ProfileService.ts: Restore working endpoint and simplify response parsing
Testing: Profile loading now works correctly for both existing and new profiles,
location data is properly extracted and displayed, maps render correctly.
This commit is contained in:
207
src/services/ServiceInitializationManager.ts
Normal file
207
src/services/ServiceInitializationManager.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Service Initialization Manager
|
||||
*
|
||||
* Manages the proper initialization order of services to prevent race conditions
|
||||
* and ensure dependencies are available when services are created.
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
* @since 2025-08-25
|
||||
*/
|
||||
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
/**
|
||||
* Service initialization status tracking
|
||||
*/
|
||||
interface ServiceStatus {
|
||||
name: string;
|
||||
initialized: boolean;
|
||||
dependencies: string[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service initialization manager to prevent race conditions
|
||||
*/
|
||||
export class ServiceInitializationManager {
|
||||
private static instance: ServiceInitializationManager;
|
||||
private serviceStatuses = new Map<string, ServiceStatus>();
|
||||
private initializationPromise: Promise<void> | null = null;
|
||||
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
* Get singleton instance
|
||||
*/
|
||||
static getInstance(): ServiceInitializationManager {
|
||||
if (!ServiceInitializationManager.instance) {
|
||||
ServiceInitializationManager.instance =
|
||||
new ServiceInitializationManager();
|
||||
}
|
||||
return ServiceInitializationManager.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a service that needs initialization
|
||||
*/
|
||||
registerService(name: string, dependencies: string[] = []): void {
|
||||
this.serviceStatuses.set(name, {
|
||||
name,
|
||||
initialized: false,
|
||||
dependencies,
|
||||
});
|
||||
|
||||
logger.debug("[ServiceInit] 🔧 Service registered:", {
|
||||
name,
|
||||
dependencies,
|
||||
totalServices: this.serviceStatuses.size,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a service as initialized
|
||||
*/
|
||||
markInitialized(name: string): void {
|
||||
const status = this.serviceStatuses.get(name);
|
||||
if (status) {
|
||||
status.initialized = true;
|
||||
logger.debug("[ServiceInit] ✅ Service initialized:", {
|
||||
name,
|
||||
totalInitialized: this.getInitializedCount(),
|
||||
totalServices: this.serviceStatuses.size,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a service as failed
|
||||
*/
|
||||
markFailed(name: string, error: string): void {
|
||||
const status = this.serviceStatuses.get(name);
|
||||
if (status) {
|
||||
status.error = error;
|
||||
logger.error("[ServiceInit] ❌ Service failed:", {
|
||||
name,
|
||||
error,
|
||||
totalFailed: this.getFailedCount(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of initialized services
|
||||
*/
|
||||
private getInitializedCount(): number {
|
||||
return Array.from(this.serviceStatuses.values()).filter(
|
||||
(s) => s.initialized,
|
||||
).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of failed services
|
||||
*/
|
||||
private getFailedCount(): number {
|
||||
return Array.from(this.serviceStatuses.values()).filter((s) => s.error)
|
||||
.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for all services to be initialized
|
||||
*/
|
||||
async waitForInitialization(): Promise<void> {
|
||||
if (this.initializationPromise) {
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
this.initializationPromise = new Promise((resolve, reject) => {
|
||||
const checkInterval = setInterval(() => {
|
||||
const totalServices = this.serviceStatuses.size;
|
||||
const initializedCount = this.getInitializedCount();
|
||||
const failedCount = this.getFailedCount();
|
||||
|
||||
logger.debug("[ServiceInit] 🔍 Initialization progress:", {
|
||||
totalServices,
|
||||
initializedCount,
|
||||
failedCount,
|
||||
remaining: totalServices - initializedCount - failedCount,
|
||||
});
|
||||
|
||||
if (failedCount > 0) {
|
||||
clearInterval(checkInterval);
|
||||
const failedServices = Array.from(this.serviceStatuses.values())
|
||||
.filter((s) => s.error)
|
||||
.map((s) => `${s.name}: ${s.error}`);
|
||||
|
||||
const error = new Error(
|
||||
`Service initialization failed: ${failedServices.join(", ")}`,
|
||||
);
|
||||
logger.error("[ServiceInit] ❌ Initialization failed:", error);
|
||||
reject(error);
|
||||
} else if (initializedCount === totalServices) {
|
||||
clearInterval(checkInterval);
|
||||
logger.info(
|
||||
"[ServiceInit] 🎉 All services initialized successfully:",
|
||||
{
|
||||
totalServices,
|
||||
initializedCount,
|
||||
},
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// Timeout after 30 seconds
|
||||
setTimeout(() => {
|
||||
clearInterval(checkInterval);
|
||||
const error = new Error(
|
||||
"Service initialization timeout after 30 seconds",
|
||||
);
|
||||
logger.error("[ServiceInit] ⏰ Initialization timeout:", error);
|
||||
reject(error);
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get initialization status summary
|
||||
*/
|
||||
getStatusSummary(): {
|
||||
total: number;
|
||||
initialized: number;
|
||||
failed: number;
|
||||
pending: number;
|
||||
services: ServiceStatus[];
|
||||
} {
|
||||
const services = Array.from(this.serviceStatuses.values());
|
||||
const total = services.length;
|
||||
const initialized = services.filter((s) => s.initialized).length;
|
||||
const failed = services.filter((s) => s.error).length;
|
||||
const pending = total - initialized - failed;
|
||||
|
||||
return {
|
||||
total,
|
||||
initialized,
|
||||
failed,
|
||||
pending,
|
||||
services,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the manager (useful for testing)
|
||||
*/
|
||||
reset(): void {
|
||||
this.serviceStatuses.clear();
|
||||
this.initializationPromise = null;
|
||||
logger.debug("[ServiceInit] 🔄 Manager reset");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to get the service initialization manager
|
||||
*/
|
||||
export const getServiceInitManager = (): ServiceInitializationManager => {
|
||||
return ServiceInitializationManager.getInstance();
|
||||
};
|
||||
Reference in New Issue
Block a user