You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
4.0 KiB
108 lines
4.0 KiB
/**
|
|
* Preload script for Electron
|
|
* Sets up secure IPC communication between renderer and main process
|
|
*
|
|
* @author Matthew Raymer
|
|
*/
|
|
|
|
import { contextBridge, ipcRenderer } from 'electron';
|
|
|
|
// Simple logger for preload script
|
|
const logger = {
|
|
log: (...args: unknown[]) => console.log('[Preload]', ...args),
|
|
error: (...args: unknown[]) => console.error('[Preload]', ...args),
|
|
info: (...args: unknown[]) => console.info('[Preload]', ...args),
|
|
warn: (...args: unknown[]) => console.warn('[Preload]', ...args),
|
|
debug: (...args: unknown[]) => console.debug('[Preload]', ...args),
|
|
};
|
|
|
|
// Types for SQLite connection options
|
|
interface SQLiteConnectionOptions {
|
|
database: string;
|
|
version?: number;
|
|
readOnly?: boolean;
|
|
readonly?: boolean; // Handle both cases
|
|
encryption?: string;
|
|
mode?: string;
|
|
useNative?: boolean;
|
|
[key: string]: unknown; // Allow other properties
|
|
}
|
|
|
|
// Create a proxy for the CapacitorSQLite plugin
|
|
const createSQLiteProxy = () => {
|
|
const MAX_RETRIES = 3;
|
|
const RETRY_DELAY = 1000; // 1 second
|
|
|
|
const withRetry = async <T>(operation: (...args: unknown[]) => Promise<T>, ...args: unknown[]): Promise<T> => {
|
|
let lastError: Error | null = null;
|
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
try {
|
|
return await operation(...args);
|
|
} catch (error) {
|
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
if (attempt < MAX_RETRIES) {
|
|
logger.warn(`[CapacitorSQLite] SQLite operation failed (attempt ${attempt}/${MAX_RETRIES}), retrying...`, error);
|
|
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
|
|
}
|
|
}
|
|
}
|
|
throw new Error(`[CapacitorSQLite] SQLite operation failed after ${MAX_RETRIES} attempts: ${lastError?.message || 'Unknown error'}`);
|
|
};
|
|
|
|
const wrapOperation = (method: string) => {
|
|
return async (...args: unknown[]): Promise<unknown> => {
|
|
try {
|
|
// For createConnection, ensure readOnly is false
|
|
if (method === 'create-connection') {
|
|
const options = args[0] as SQLiteConnectionOptions;
|
|
if (options && typeof options === 'object') {
|
|
// Set readOnly to false and ensure mode is rwc
|
|
options.readOnly = false;
|
|
options.mode = 'rwc';
|
|
// Remove any lowercase readonly property if it exists
|
|
delete options.readonly;
|
|
}
|
|
}
|
|
return await withRetry(ipcRenderer.invoke, 'sqlite-' + method, ...args);
|
|
} catch (error) {
|
|
logger.error(`[CapacitorSQLite] SQLite ${method} failed:`, error);
|
|
throw new Error(`[CapacitorSQLite] Database operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
}
|
|
};
|
|
};
|
|
|
|
// Create a proxy that matches the CapacitorSQLite interface
|
|
return {
|
|
echo: wrapOperation('echo'),
|
|
createConnection: wrapOperation('create-connection'),
|
|
closeConnection: wrapOperation('close-connection'),
|
|
execute: wrapOperation('execute'),
|
|
query: wrapOperation('query'),
|
|
run: wrapOperation('run'),
|
|
isAvailable: wrapOperation('is-available'),
|
|
getPlatform: () => Promise.resolve('electron'),
|
|
// Add other methods as needed
|
|
};
|
|
};
|
|
|
|
// Expose the Electron IPC API
|
|
contextBridge.exposeInMainWorld('electron', {
|
|
ipcRenderer: {
|
|
on: (channel: string, func: (...args: unknown[]) => void) => ipcRenderer.on(channel, (event, ...args) => func(...args)),
|
|
once: (channel: string, func: (...args: unknown[]) => void) => ipcRenderer.once(channel, (event, ...args) => func(...args)),
|
|
send: (channel: string, data: unknown) => ipcRenderer.send(channel, data),
|
|
invoke: (channel: string, ...args: unknown[]) => ipcRenderer.invoke(channel, ...args),
|
|
},
|
|
// Add other APIs as needed
|
|
});
|
|
|
|
// Expose CapacitorSQLite proxy as before
|
|
contextBridge.exposeInMainWorld('CapacitorSQLite', createSQLiteProxy());
|
|
|
|
// Log startup
|
|
logger.log('[CapacitorSQLite] Preload script starting...');
|
|
|
|
// Handle window load
|
|
window.addEventListener('load', () => {
|
|
logger.log('[CapacitorSQLite] Preload script complete');
|
|
});
|
|
|