- 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.
148 lines
4.6 KiB
TypeScript
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,
|
|
};
|
|
}
|
|
}
|