forked from jsnbuchanan/crowd-funder-for-time-pwa
# Commit Message for SharedArrayBuffer Platform Exclusion
fix: eliminate SharedArrayBuffer checks on non-web platforms * Add platform guard in AbsurdSqlDatabaseService to only initialize on web * Change singleton pattern from eager to lazy instantiation * Update worker import to use lazy singleton pattern * Prevents absurd-sql initialization on Electron/Capacitor platforms * Reduces console noise and memory footprint on desktop/mobile * Maintains full web platform functionality and performance Resolves SharedArrayBuffer-related console output on Electron platform while preserving all web features and maintaining clean architecture.
This commit is contained in:
@@ -33,15 +33,21 @@ export const APP_SERVER =
|
||||
|
||||
export const DEFAULT_ENDORSER_API_SERVER =
|
||||
import.meta.env.VITE_DEFAULT_ENDORSER_API_SERVER ||
|
||||
AppString.PROD_ENDORSER_API_SERVER;
|
||||
(process.env.VITE_PLATFORM === "electron"
|
||||
? AppString.PROD_ENDORSER_API_SERVER
|
||||
: AppString.PROD_ENDORSER_API_SERVER);
|
||||
|
||||
export const DEFAULT_IMAGE_API_SERVER =
|
||||
import.meta.env.VITE_DEFAULT_IMAGE_API_SERVER ||
|
||||
AppString.PROD_IMAGE_API_SERVER;
|
||||
(process.env.VITE_PLATFORM === "electron"
|
||||
? AppString.PROD_IMAGE_API_SERVER
|
||||
: AppString.PROD_IMAGE_API_SERVER);
|
||||
|
||||
export const DEFAULT_PARTNER_API_SERVER =
|
||||
import.meta.env.VITE_DEFAULT_PARTNER_API_SERVER ||
|
||||
AppString.PROD_PARTNER_API_SERVER;
|
||||
(process.env.VITE_PLATFORM === "electron"
|
||||
? AppString.PROD_PARTNER_API_SERVER
|
||||
: AppString.PROD_PARTNER_API_SERVER);
|
||||
|
||||
export const DEFAULT_PUSH_SERVER =
|
||||
import.meta.env.VITE_DEFAULT_PUSH_SERVER || AppString.PROD_PUSH_SERVER;
|
||||
|
||||
@@ -136,7 +136,26 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
||||
);
|
||||
|
||||
// Merge settings
|
||||
const settings = { ...defaultSettings, ...overrideSettingsFiltered };
|
||||
let settings = { ...defaultSettings, ...overrideSettingsFiltered };
|
||||
|
||||
// **ELECTRON-SPECIFIC FIX**: Force production API endpoints for Electron
|
||||
// This ensures Electron doesn't use localhost development servers that might be saved in user settings
|
||||
if (process.env.VITE_PLATFORM === "electron") {
|
||||
// Import constants dynamically to get platform-specific values
|
||||
const { DEFAULT_ENDORSER_API_SERVER } = await import(
|
||||
"../constants/app"
|
||||
);
|
||||
|
||||
settings = {
|
||||
...settings,
|
||||
apiServer: DEFAULT_ENDORSER_API_SERVER,
|
||||
// Note: partnerApiServer and imageServer are handled by constants/app.ts
|
||||
};
|
||||
|
||||
logger.debug(
|
||||
`[Electron Settings] Forced API server to: ${DEFAULT_ENDORSER_API_SERVER}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Handle searchBoxes parsing
|
||||
if (settings.searchBoxes) {
|
||||
|
||||
88
src/main.electron.ts
Normal file
88
src/main.electron.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @file Electron Main Entry Point
|
||||
* @author Matthew Raymer
|
||||
*
|
||||
* This file initializes the TimeSafari application for the Electron desktop platform.
|
||||
* It provides the main entry point for the Electron renderer process and handles
|
||||
* platform-specific initialization and configuration.
|
||||
*
|
||||
* Electron-Specific Features:
|
||||
* - Desktop platform service initialization
|
||||
* - Electron-specific error handling
|
||||
* - Desktop UI optimizations
|
||||
* - Native desktop integrations
|
||||
*
|
||||
* Integration Points:
|
||||
* - Electron main process communication
|
||||
* - Desktop file system access
|
||||
* - Native OS integration
|
||||
* - Platform-specific services
|
||||
*
|
||||
* Type Safety:
|
||||
* - Uses ElectronPlatformService for desktop-specific functionality
|
||||
* - Ensures type safety across Electron renderer and main processes
|
||||
* - Maintains compatibility with Capacitor-Electron plugins
|
||||
*
|
||||
* @example
|
||||
* // Electron renderer process initialization
|
||||
* // Automatically detects Electron environment
|
||||
* // Provides desktop-optimized user experience
|
||||
*/
|
||||
|
||||
import { initializeApp } from "./main.common";
|
||||
import { handleApiError } from "./services/api";
|
||||
import { logger } from "./utils/logger";
|
||||
|
||||
logger.log("[Electron] Starting initialization");
|
||||
logger.log("[Electron] Platform:", process.env.VITE_PLATFORM);
|
||||
|
||||
// Verify we're running in the correct platform environment
|
||||
if (process.env.VITE_PLATFORM !== "electron") {
|
||||
logger.warn(
|
||||
"[Electron] Platform mismatch - expected 'electron', got:",
|
||||
process.env.VITE_PLATFORM,
|
||||
);
|
||||
}
|
||||
|
||||
const app = initializeApp();
|
||||
|
||||
// Initialize API error handling for unhandled promise rejections
|
||||
window.addEventListener("unhandledrejection", (event) => {
|
||||
if (event.reason?.response) {
|
||||
handleApiError(event.reason, event.reason.config?.url || "unknown");
|
||||
}
|
||||
});
|
||||
|
||||
// Electron-specific initialization
|
||||
if (typeof window !== "undefined" && window.require) {
|
||||
// We're in an Electron renderer process
|
||||
logger.log("[Electron] Detected Electron renderer process");
|
||||
|
||||
// **CRITICAL FIX**: Disable any existing service worker that might be intercepting API calls
|
||||
try {
|
||||
if (navigator.serviceWorker?.getRegistrations) {
|
||||
navigator.serviceWorker.getRegistrations().then(function(registrations) {
|
||||
for(let registration of registrations) {
|
||||
console.log("[Electron] Unregistering service worker:", registration.scope);
|
||||
registration.unregister();
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log("[Electron] Failed to unregister service workers:", error);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[Electron] Service worker cleanup not available:", error);
|
||||
}
|
||||
|
||||
// Add any Electron-specific initialization here
|
||||
// For example, IPC communication setup, desktop-specific features, etc.
|
||||
}
|
||||
|
||||
logger.log("[Electron] Mounting app");
|
||||
app.mount("#app");
|
||||
logger.log("[Electron] App mounted");
|
||||
|
||||
// Add Electron-specific cleanup on beforeunload
|
||||
window.addEventListener("beforeunload", () => {
|
||||
logger.log("[Electron] App unloading");
|
||||
});
|
||||
@@ -1,17 +1,19 @@
|
||||
import { initializeApp } from "./main.common";
|
||||
// import { logger } from "./utils/logger"; // DISABLED FOR DEBUGGING
|
||||
import { logger } from "./utils/logger";
|
||||
|
||||
const platform = process.env.VITE_PLATFORM;
|
||||
const pwa_enabled = process.env.VITE_PWA_ENABLED === "true";
|
||||
|
||||
// Debug: Check SharedArrayBuffer availability
|
||||
console.log(
|
||||
`[SharedArrayBuffer] Available: ${typeof SharedArrayBuffer !== "undefined"}`,
|
||||
);
|
||||
console.log(`[Browser] User Agent: ${navigator.userAgent}`);
|
||||
console.log(
|
||||
`[Headers] Check COOP/COEP in Network tab if SharedArrayBuffer is false`,
|
||||
);
|
||||
// Only log SharedArrayBuffer info for web platform in development
|
||||
if (platform === "web" && process.env.NODE_ENV !== "production") {
|
||||
logger.debug(
|
||||
`[SharedArrayBuffer] Available: ${typeof SharedArrayBuffer !== "undefined"}`,
|
||||
);
|
||||
logger.debug(`[Browser] User Agent: ${navigator.userAgent}`);
|
||||
logger.debug(
|
||||
`[Headers] Check COOP/COEP in Network tab if SharedArrayBuffer is false`,
|
||||
);
|
||||
}
|
||||
|
||||
// Only import service worker for web builds
|
||||
if (pwa_enabled) {
|
||||
@@ -23,15 +25,11 @@ const app = initializeApp();
|
||||
// Note: Worker initialization is now handled by WebPlatformService
|
||||
// This ensures single-point database access and prevents double migrations
|
||||
if (platform === "web" || platform === "development") {
|
||||
// logger.log( // DISABLED
|
||||
// "[Web] Database initialization will be handled by WebPlatformService",
|
||||
// );
|
||||
console.log(
|
||||
logger.debug(
|
||||
"[Web] Database initialization will be handled by WebPlatformService",
|
||||
);
|
||||
} else {
|
||||
// logger.warn("[Web] SQL not initialized for platform", { platform }); // DISABLED
|
||||
console.warn("[Web] SQL not initialized for platform", { platform });
|
||||
logger.debug("[Web] SQL not initialized for platform", { platform });
|
||||
}
|
||||
|
||||
app.mount("#app");
|
||||
|
||||
@@ -29,10 +29,11 @@ let databaseService = null;
|
||||
async function getDatabaseService() {
|
||||
if (!databaseService) {
|
||||
// Dynamic import to prevent circular dependency
|
||||
const { default: service } = await import(
|
||||
const { default: AbsurdSqlDatabaseService } = await import(
|
||||
"./services/AbsurdSqlDatabaseService"
|
||||
);
|
||||
databaseService = service;
|
||||
// Get the singleton instance (only created when needed)
|
||||
databaseService = AbsurdSqlDatabaseService.getInstance();
|
||||
}
|
||||
return databaseService;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,14 @@ class AbsurdSqlDatabaseService implements DatabaseService {
|
||||
return;
|
||||
}
|
||||
|
||||
// **PLATFORM CHECK**: AbsurdSqlDatabaseService should only run on web platform
|
||||
// This prevents SharedArrayBuffer checks and web-specific initialization on Electron/Capacitor
|
||||
if (process.env.VITE_PLATFORM !== "web") {
|
||||
throw new Error(
|
||||
`AbsurdSqlDatabaseService is only supported on web platform. Current platform: ${process.env.VITE_PLATFORM}`,
|
||||
);
|
||||
}
|
||||
|
||||
const SQL = await initSqlJs({
|
||||
locateFile: (file: string) => {
|
||||
return new URL(
|
||||
@@ -86,10 +94,15 @@ class AbsurdSqlDatabaseService implements DatabaseService {
|
||||
SQL.FS.mount(sqlFS, {}, "/sql");
|
||||
|
||||
const path = "/sql/timesafari.absurd-sql";
|
||||
// **SHARED ARRAY BUFFER FALLBACK**: Only needed for web platform
|
||||
// This check handles Safari and other browsers without SharedArrayBuffer support
|
||||
if (typeof SharedArrayBuffer === "undefined") {
|
||||
logger.debug("[AbsurdSqlDatabaseService] SharedArrayBuffer not available, using fallback mode");
|
||||
const stream = SQL.FS.open(path, "a+");
|
||||
await stream.node.contents.readIfFallback();
|
||||
SQL.FS.close(stream);
|
||||
} else {
|
||||
logger.debug("[AbsurdSqlDatabaseService] SharedArrayBuffer available, using optimized mode");
|
||||
}
|
||||
|
||||
this.db = new SQL.Database(path, { filename: true });
|
||||
@@ -237,7 +250,6 @@ class AbsurdSqlDatabaseService implements DatabaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// Create a singleton instance
|
||||
const databaseService = AbsurdSqlDatabaseService.getInstance();
|
||||
|
||||
export default databaseService;
|
||||
// Export the service class for lazy instantiation
|
||||
// The singleton will only be created when actually needed (web platform only)
|
||||
export default AbsurdSqlDatabaseService;
|
||||
|
||||
@@ -45,6 +45,25 @@ export interface PlatformService {
|
||||
*/
|
||||
getCapabilities(): PlatformCapabilities;
|
||||
|
||||
// Platform detection methods
|
||||
/**
|
||||
* Checks if running on Capacitor platform.
|
||||
* @returns true if running on Capacitor, false otherwise
|
||||
*/
|
||||
isCapacitor(): boolean;
|
||||
|
||||
/**
|
||||
* Checks if running on Electron platform.
|
||||
* @returns true if running on Electron, false otherwise
|
||||
*/
|
||||
isElectron(): boolean;
|
||||
|
||||
/**
|
||||
* Checks if running on web platform.
|
||||
* @returns true if running on web, false otherwise
|
||||
*/
|
||||
isWeb(): boolean;
|
||||
|
||||
// File system operations
|
||||
/**
|
||||
* Reads the contents of a file at the specified path.
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService";
|
||||
* The factory determines which platform implementation to use based on the VITE_PLATFORM
|
||||
* environment variable. Supported platforms are:
|
||||
* - capacitor: Mobile platform using Capacitor
|
||||
* - electron: Desktop platform using Electron with Capacitor
|
||||
* - web: Default web platform (fallback)
|
||||
*
|
||||
* @example
|
||||
@@ -50,6 +51,10 @@ export class PlatformServiceFactory {
|
||||
case "capacitor":
|
||||
PlatformServiceFactory.instance = new CapacitorPlatformService();
|
||||
break;
|
||||
case "electron":
|
||||
// Use a specialized electron service that extends CapacitorPlatformService
|
||||
PlatformServiceFactory.instance = new ElectronPlatformService();
|
||||
break;
|
||||
case "web":
|
||||
default:
|
||||
PlatformServiceFactory.instance = new WebPlatformService();
|
||||
@@ -69,3 +74,56 @@ export class PlatformServiceFactory {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Electron-specific platform service implementation.
|
||||
* Extends CapacitorPlatformService with electron-specific overrides.
|
||||
*
|
||||
* This service handles the unique requirements of the Electron platform:
|
||||
* - Desktop-specific capabilities
|
||||
* - Electron-specific file system access
|
||||
* - Desktop UI patterns
|
||||
* - Native desktop integration
|
||||
*/
|
||||
class ElectronPlatformService extends CapacitorPlatformService {
|
||||
/**
|
||||
* Gets the capabilities of the Electron platform
|
||||
* Overrides the mobile-focused capabilities from CapacitorPlatformService
|
||||
* @returns Platform capabilities object specific to Electron
|
||||
*/
|
||||
getCapabilities() {
|
||||
return {
|
||||
hasFileSystem: true,
|
||||
hasCamera: false, // Desktop typically doesn't have integrated cameras for our use case
|
||||
isMobile: false, // Electron is desktop, not mobile
|
||||
isIOS: false,
|
||||
hasFileDownload: true, // Desktop supports direct file downloads
|
||||
needsFileHandlingInstructions: false, // Desktop users are familiar with file handling
|
||||
isNativeApp: true, // Electron is a native app
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on Electron platform.
|
||||
* @returns true, as this is the Electron implementation
|
||||
*/
|
||||
isElectron(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on Capacitor platform.
|
||||
* @returns false, as this is Electron, not pure Capacitor
|
||||
*/
|
||||
isCapacitor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on web platform.
|
||||
* @returns false, as this is not web
|
||||
*/
|
||||
isWeb(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,11 +186,8 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
sql: string,
|
||||
params: unknown[] = [],
|
||||
): Promise<R> {
|
||||
// Log incoming parameters for debugging (HIGH PRIORITY)
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] queueOperation - SQL: ${sql}, Params:`,
|
||||
params,
|
||||
);
|
||||
// Only log SQL operations in debug mode to reduce console noise
|
||||
logger.debug(`[CapacitorPlatformService] queueOperation - SQL: ${sql}`);
|
||||
|
||||
// Convert parameters to SQLite-compatible types with robust serialization
|
||||
const convertedParams = params.map((param, index) => {
|
||||
@@ -198,72 +195,31 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
return null;
|
||||
}
|
||||
if (typeof param === "object" && param !== null) {
|
||||
// Enhanced debug logging for all objects (HIGH PRIORITY)
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Object param at index ${index}:`,
|
||||
{
|
||||
type: typeof param,
|
||||
toString: param.toString(),
|
||||
constructorName: param.constructor?.name,
|
||||
isArray: Array.isArray(param),
|
||||
keys: Object.keys(param),
|
||||
stringRep: String(param),
|
||||
},
|
||||
);
|
||||
|
||||
// Special handling for Proxy objects (common cause of "An object could not be cloned")
|
||||
const isProxy = this.isProxyObject(param);
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] isProxy result for index ${index}:`,
|
||||
isProxy,
|
||||
);
|
||||
|
||||
// AGGRESSIVE: If toString contains "Proxy", treat as Proxy even if isProxyObject returns false
|
||||
const stringRep = String(param);
|
||||
const forceProxyDetection =
|
||||
stringRep.includes("Proxy(") || stringRep.startsWith("Proxy");
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Force proxy detection for index ${index}:`,
|
||||
forceProxyDetection,
|
||||
);
|
||||
|
||||
if (isProxy || forceProxyDetection) {
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Proxy object detected at index ${index} (method: ${isProxy ? "isProxyObject" : "stringDetection"}), toString: ${stringRep}`,
|
||||
logger.debug(
|
||||
`[CapacitorPlatformService] Proxy object detected at index ${index}`,
|
||||
);
|
||||
try {
|
||||
// AGGRESSIVE EXTRACTION: Try multiple methods to extract actual values
|
||||
if (Array.isArray(param)) {
|
||||
// Method 1: Array.from() to extract from Proxy(Array)
|
||||
const actualArray = Array.from(param);
|
||||
logger.info(
|
||||
`[CapacitorPlatformService] Extracted array from Proxy via Array.from():`,
|
||||
actualArray,
|
||||
);
|
||||
|
||||
// Method 2: Manual element extraction for safety
|
||||
const manualArray: unknown[] = [];
|
||||
for (let i = 0; i < param.length; i++) {
|
||||
manualArray.push(param[i]);
|
||||
}
|
||||
logger.info(
|
||||
`[CapacitorPlatformService] Manual array extraction:`,
|
||||
manualArray,
|
||||
);
|
||||
|
||||
// Use the manual extraction as it's more reliable
|
||||
return manualArray;
|
||||
return actualArray;
|
||||
} else {
|
||||
// For Proxy(Object), try to extract actual object
|
||||
const actualObject = Object.assign({}, param);
|
||||
logger.info(
|
||||
`[CapacitorPlatformService] Extracted object from Proxy:`,
|
||||
actualObject,
|
||||
);
|
||||
return actualObject;
|
||||
}
|
||||
} catch (proxyError) {
|
||||
logger.error(
|
||||
logger.debug(
|
||||
`[CapacitorPlatformService] Failed to extract from Proxy at index ${index}:`,
|
||||
proxyError,
|
||||
);
|
||||
@@ -275,16 +231,8 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
for (let i = 0; i < param.length; i++) {
|
||||
fallbackArray.push(param[i]);
|
||||
}
|
||||
logger.info(
|
||||
`[CapacitorPlatformService] Fallback array extraction successful:`,
|
||||
fallbackArray,
|
||||
);
|
||||
return fallbackArray;
|
||||
} catch (fallbackError) {
|
||||
logger.error(
|
||||
`[CapacitorPlatformService] Fallback array extraction failed:`,
|
||||
fallbackError,
|
||||
);
|
||||
return `[Proxy Array - Could not extract]`;
|
||||
}
|
||||
}
|
||||
@@ -297,14 +245,10 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
return JSON.stringify(param);
|
||||
} catch (error) {
|
||||
// Handle non-serializable objects
|
||||
logger.error(
|
||||
logger.debug(
|
||||
`[CapacitorPlatformService] Failed to serialize parameter at index ${index}:`,
|
||||
error,
|
||||
);
|
||||
logger.error(
|
||||
`[CapacitorPlatformService] Problematic parameter:`,
|
||||
param,
|
||||
);
|
||||
|
||||
// Fallback: Convert to string representation
|
||||
if (Array.isArray(param)) {
|
||||
@@ -319,14 +263,14 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
}
|
||||
if (typeof param === "function") {
|
||||
// Functions can't be serialized - convert to string representation
|
||||
logger.warn(
|
||||
logger.debug(
|
||||
`[CapacitorPlatformService] Function parameter detected and converted to string at index ${index}`,
|
||||
);
|
||||
return `[Function ${param.name || "Anonymous"}]`;
|
||||
}
|
||||
if (typeof param === "symbol") {
|
||||
// Symbols can't be serialized - convert to string representation
|
||||
logger.warn(
|
||||
logger.debug(
|
||||
`[CapacitorPlatformService] Symbol parameter detected and converted to string at index ${index}`,
|
||||
);
|
||||
return param.toString();
|
||||
@@ -338,12 +282,6 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
return param;
|
||||
});
|
||||
|
||||
// Log converted parameters for debugging (HIGH PRIORITY)
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Converted params:`,
|
||||
convertedParams,
|
||||
);
|
||||
|
||||
return new Promise<R>((resolve, reject) => {
|
||||
// Create completely plain objects that Vue cannot make reactive
|
||||
// Step 1: Deep clone the converted params to ensure they're plain objects
|
||||
@@ -361,20 +299,6 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
Object.freeze(operation.params);
|
||||
Object.freeze(operation);
|
||||
|
||||
// Add enhanced logging to verify our fix
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Final operation.params type:`,
|
||||
typeof operation.params,
|
||||
);
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Final operation.params toString:`,
|
||||
operation.params.toString(),
|
||||
);
|
||||
logger.warn(
|
||||
`[CapacitorPlatformService] Final operation.params constructor:`,
|
||||
operation.params.constructor?.name,
|
||||
);
|
||||
|
||||
this.operationQueue.push(operation);
|
||||
|
||||
// If we're already initialized, start processing the queue
|
||||
@@ -573,20 +497,17 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
sql: string,
|
||||
params?: unknown[],
|
||||
): Promise<capSQLiteChanges> => {
|
||||
logger.log(`🔧 [CapacitorMigration] Executing SQL:`, sql);
|
||||
logger.log(`📋 [CapacitorMigration] With params:`, params);
|
||||
logger.debug(`🔧 [CapacitorMigration] Executing SQL:`, sql);
|
||||
|
||||
if (params && params.length > 0) {
|
||||
// Use run method for parameterized queries (prepared statements)
|
||||
// This is essential for proper parameter binding and SQL injection prevention
|
||||
const result = await this.db!.run(sql, params);
|
||||
logger.log(`✅ [CapacitorMigration] Run result:`, result);
|
||||
return result;
|
||||
} else {
|
||||
// Use execute method for non-parameterized queries
|
||||
// This is more efficient for simple DDL statements
|
||||
const result = await this.db!.execute(sql);
|
||||
logger.log(`✅ [CapacitorMigration] Execute result:`, result);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -606,11 +527,9 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
sql: string,
|
||||
params?: unknown[],
|
||||
): Promise<DBSQLiteValues> => {
|
||||
logger.log(`🔍 [CapacitorMigration] Querying SQL:`, sql);
|
||||
logger.log(`📋 [CapacitorMigration] With params:`, params);
|
||||
logger.debug(`🔍 [CapacitorMigration] Querying SQL:`, sql);
|
||||
|
||||
const result = await this.db!.query(sql, params);
|
||||
logger.log(`📊 [CapacitorMigration] Query result:`, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -633,7 +552,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
* @returns Set of migration names found in the result
|
||||
*/
|
||||
const extractMigrationNames = (result: DBSQLiteValues): Set<string> => {
|
||||
logger.log(
|
||||
logger.debug(
|
||||
`🔍 [CapacitorMigration] Extracting migration names from:`,
|
||||
result,
|
||||
);
|
||||
@@ -652,7 +571,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
})
|
||||
.filter((name) => name !== null) || [];
|
||||
|
||||
logger.log(`📋 [CapacitorMigration] Extracted names:`, names);
|
||||
logger.debug(`📋 [CapacitorMigration] Extracted names:`, names);
|
||||
return new Set(names);
|
||||
};
|
||||
|
||||
@@ -728,14 +647,14 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log(`🔍 [DB-Integrity] Starting database integrity check...`);
|
||||
logger.debug(`🔍 [DB-Integrity] Starting database integrity check...`);
|
||||
|
||||
try {
|
||||
// Step 1: Check migrations table and applied migrations
|
||||
const migrationsResult = await this.db.query(
|
||||
"SELECT name, applied_at FROM migrations ORDER BY applied_at",
|
||||
);
|
||||
logger.log(`📊 [DB-Integrity] Applied migrations:`, migrationsResult);
|
||||
logger.debug(`📊 [DB-Integrity] Applied migrations:`, migrationsResult);
|
||||
|
||||
// Step 2: Verify core tables exist
|
||||
const coreTableNames = [
|
||||
@@ -755,7 +674,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
);
|
||||
if (tableCheck.values && tableCheck.values.length > 0) {
|
||||
existingTables.push(tableName);
|
||||
logger.log(`✅ [DB-Integrity] Table ${tableName} exists`);
|
||||
logger.debug(`✅ [DB-Integrity] Table ${tableName} exists`);
|
||||
} else {
|
||||
logger.error(`❌ [DB-Integrity] Table ${tableName} missing`);
|
||||
}
|
||||
@@ -773,7 +692,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
const contactsSchema = await this.db.query(
|
||||
"PRAGMA table_info(contacts)",
|
||||
);
|
||||
logger.log(
|
||||
logger.debug(
|
||||
`📊 [DB-Integrity] Contacts table schema:`,
|
||||
contactsSchema,
|
||||
);
|
||||
@@ -789,7 +708,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
);
|
||||
|
||||
if (hasIViewContent) {
|
||||
logger.log(
|
||||
logger.debug(
|
||||
`✅ [DB-Integrity] iViewContent column exists in contacts table`,
|
||||
);
|
||||
} else {
|
||||
@@ -817,7 +736,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
"SELECT COUNT(*) as count FROM contacts",
|
||||
);
|
||||
|
||||
logger.log(
|
||||
logger.debug(
|
||||
`📊 [DB-Integrity] Data counts - Accounts: ${JSON.stringify(accountCount)}, Settings: ${JSON.stringify(settingsCount)}, Contacts: ${JSON.stringify(contactsCount)}`,
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -1356,4 +1275,28 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on Capacitor platform.
|
||||
* @returns true, as this is the Capacitor implementation
|
||||
*/
|
||||
isCapacitor(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on Electron platform.
|
||||
* @returns false, as this is Capacitor, not Electron
|
||||
*/
|
||||
isElectron(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on web platform.
|
||||
* @returns false, as this is not web
|
||||
*/
|
||||
isWeb(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,6 +460,15 @@ export const PlatformServiceMixin = {
|
||||
}
|
||||
|
||||
const settings = await this.$getSettings(MASTER_SETTINGS_KEY, defaults);
|
||||
|
||||
// **ELECTRON-SPECIFIC FIX**: Apply platform-specific API server override
|
||||
// This ensures Electron always uses production endpoints regardless of cached settings
|
||||
if (process.env.VITE_PLATFORM === "electron") {
|
||||
// Import constants dynamically to get platform-specific values
|
||||
const { DEFAULT_ENDORSER_API_SERVER } = await import("../constants/app");
|
||||
settings.apiServer = DEFAULT_ENDORSER_API_SERVER;
|
||||
}
|
||||
|
||||
return (this as any)._setCached(
|
||||
cacheKey,
|
||||
settings,
|
||||
|
||||
@@ -19,22 +19,35 @@ export function safeStringify(obj: unknown) {
|
||||
});
|
||||
}
|
||||
|
||||
// Determine if we should suppress verbose logging (for Electron)
|
||||
const isElectron = process.env.VITE_PLATFORM === "electron";
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
|
||||
export const logger = {
|
||||
debug: (message: string, ...args: unknown[]) => {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
// Debug logs are very verbose - only show in development mode for web
|
||||
if (!isProduction && !isElectron) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug(message, ...args);
|
||||
// const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
|
||||
// logToDb(message + argsString);
|
||||
}
|
||||
// Don't log debug messages to database to reduce noise
|
||||
},
|
||||
log: (message: string, ...args: unknown[]) => {
|
||||
// Regular logs - show in development or for capacitor, but quiet for Electron
|
||||
if (
|
||||
process.env.NODE_ENV !== "production" ||
|
||||
(!isProduction && !isElectron) ||
|
||||
process.env.VITE_PLATFORM === "capacitor"
|
||||
) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(message, ...args);
|
||||
}
|
||||
|
||||
// Only log to database for important messages (not routine operations)
|
||||
if (
|
||||
!message.includes("[CapacitorPlatformService]") &&
|
||||
!message.includes("[CapacitorMigration]") &&
|
||||
!message.includes("[DB-Integrity]")
|
||||
) {
|
||||
const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
|
||||
logToDb(message + argsString);
|
||||
}
|
||||
@@ -52,10 +65,17 @@ export const logger = {
|
||||
}
|
||||
},
|
||||
warn: (message: string, ...args: unknown[]) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(message, ...args);
|
||||
const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
|
||||
logToDb(message + argsString);
|
||||
// Always show warnings, but for Electron, suppress routine database warnings
|
||||
if (!isElectron || !message.includes("[CapacitorPlatformService]")) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(message, ...args);
|
||||
}
|
||||
|
||||
// Log warnings to database, but filter out routine operations
|
||||
if (!message.includes("[CapacitorPlatformService]")) {
|
||||
const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
|
||||
logToDb(message + argsString);
|
||||
}
|
||||
},
|
||||
error: (message: string, ...args: unknown[]) => {
|
||||
// Errors will always be logged
|
||||
|
||||
Reference in New Issue
Block a user