Files
crowd-funder-for-time-pwa/src/services/PlatformServiceFactory.ts
Matthew Raymer 11658140ae refactor: reduce logging noise and simplify database service code
- Removed excessive debug/success logs from CapacitorPlatformService
- Removed verbose singleton tracking logs from PlatformServiceFactory
- Removed unnecessary platform !== 'web' check in applyPragmas (service only loads for Capacitor)
- Compressed try-catch blocks in applyPragmas for cleaner code
- Extracted executor adapters to createExecutor() methods in both CapacitorPlatformService and AbsurdSqlDatabaseService for consistency and testability

This reduces console noise while maintaining essential error logging.
2025-11-09 10:34:43 +00:00

148 lines
4.6 KiB
TypeScript

import { PlatformService } from "./PlatformService";
import { WebPlatformService } from "./platforms/WebPlatformService";
import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService";
import { ElectronPlatformService } from "./platforms/ElectronPlatformService";
/**
* HMR-safe global singleton storage for PlatformService
*
* Uses multiple fallbacks to ensure persistence across module reloads:
* 1. globalThis (standard, works in most environments)
* 2. window (browser fallback)
* 3. self (web worker fallback)
*/
declare global {
// eslint-disable-next-line no-var
var __PLATFORM_SERVICE_SINGLETON__: PlatformService | undefined;
}
/**
* Get the global object for singleton storage
* Uses multiple fallbacks to ensure compatibility
*/
function getGlobal(): typeof globalThis {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof window !== "undefined") return window as typeof globalThis;
if (typeof self !== "undefined") return self as typeof globalThis;
// Fallback for Node.js environments
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return {} as any;
}
/**
* Factory function to create platform-specific service implementation
*
* Uses console.log instead of logger to avoid circular dependency
* (logger imports PlatformServiceFactory)
*/
function create(): PlatformService {
const which = import.meta.env?.VITE_PLATFORM ?? "web";
if (which === "capacitor") return new CapacitorPlatformService();
if (which === "electron") return new ElectronPlatformService();
return new WebPlatformService();
}
/**
* Get or create the HMR-safe singleton instance of PlatformService
*
* Uses lazy initialization to avoid circular dependency issues at module load time.
*/
function getPlatformSvc(): PlatformService {
const global = getGlobal();
const exists = global.__PLATFORM_SERVICE_SINGLETON__ !== undefined;
if (!exists) {
global.__PLATFORM_SERVICE_SINGLETON__ = create();
// Verify it was stored
if (!global.__PLATFORM_SERVICE_SINGLETON__) {
// eslint-disable-next-line no-console
console.error(
"[PlatformServiceFactory] ERROR: Singleton creation failed - storage returned undefined",
);
}
}
// Type guard: ensure singleton exists (should never be undefined at this point)
const singleton = global.__PLATFORM_SERVICE_SINGLETON__;
if (!singleton) {
// eslint-disable-next-line no-console
console.error(
"[PlatformServiceFactory] CRITICAL: Singleton is undefined after creation/retrieval",
);
// Fallback: create a new one
global.__PLATFORM_SERVICE_SINGLETON__ = create();
return global.__PLATFORM_SERVICE_SINGLETON__;
}
return singleton;
}
/**
* HMR-safe singleton instance of PlatformService
*
* This is the ONLY way to access PlatformService throughout the application.
* Do not create new instances of platform services directly.
*
* Uses lazy initialization via Proxy to avoid circular dependency issues at module load time.
*
* @example
* ```typescript
* import { PlatformSvc } from "./services/PlatformServiceFactory";
* await PlatformSvc.takePicture();
* ```
*/
export const PlatformSvc = new Proxy({} as PlatformService, {
get(_target, prop) {
const svc = getPlatformSvc();
const value = (svc as unknown as Record<string, unknown>)[prop as string];
// Bind methods to maintain 'this' context
if (typeof value === "function") {
return value.bind(svc);
}
return value;
},
});
// Preserve singleton across Vite HMR
if (import.meta?.hot) {
import.meta.hot.accept(() => {
// Don't recreate on HMR - keep existing instance
const global = getGlobal();
if (!global.__PLATFORM_SERVICE_SINGLETON__) {
// Restore singleton if it was lost during HMR
global.__PLATFORM_SERVICE_SINGLETON__ = getPlatformSvc();
}
});
import.meta.hot.dispose(() => {
// Don't delete - keep the global instance
// The singleton will persist in globalThis/window/self
});
}
/**
* Legacy factory class for backward compatibility
* @deprecated Use `PlatformSvc` directly instead
*/
export class PlatformServiceFactory {
/**
* Gets the singleton instance of PlatformService.
* @deprecated Use `PlatformSvc` directly instead
*/
public static getInstance(): PlatformService {
return PlatformSvc;
}
/**
* Debug method to check singleton usage stats
*/
public static getStats(): { callCount: number; instanceExists: boolean } {
const global = getGlobal();
return {
callCount: 0, // Deprecated - no longer tracking
instanceExists: global.__PLATFORM_SERVICE_SINGLETON__ !== undefined,
};
}
}