Fix Vue property conflicts in PlatformServiceMixin implementation

- Remove duplicate property declarations from TopMessage component
- Use (this as any) type assertion for mixin methods
- Resolves 'Data property already defined' warnings
- Fixes 'this.dbQuery is not a function' runtime errors
This commit is contained in:
Matthew Raymer
2025-07-02 09:58:07 +00:00
parent 7b1f891c63
commit b37f1d1d84
11 changed files with 446 additions and 158 deletions

View File

@@ -187,8 +187,11 @@ export class CapacitorPlatformService implements PlatformService {
params: unknown[] = [],
): Promise<R> {
// Log incoming parameters for debugging (HIGH PRIORITY)
logger.warn(`[CapacitorPlatformService] queueOperation - SQL: ${sql}, Params:`, params);
logger.warn(
`[CapacitorPlatformService] queueOperation - SQL: ${sql}, Params:`,
params,
);
// Convert parameters to SQLite-compatible types with robust serialization
const convertedParams = params.map((param, index) => {
if (param === null || param === undefined) {
@@ -196,51 +199,75 @@ export class CapacitorPlatformService implements PlatformService {
}
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)
});
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);
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);
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.warn(
`[CapacitorPlatformService] Proxy object detected at index ${index} (method: ${isProxy ? "isProxyObject" : "stringDetection"}), toString: ${stringRep}`,
);
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);
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);
logger.info(
`[CapacitorPlatformService] Manual array extraction:`,
manualArray,
);
// Use the manual extraction as it's more reliable
return manualArray;
} else {
// For Proxy(Object), try to extract actual object
const actualObject = Object.assign({}, param);
logger.info(`[CapacitorPlatformService] Extracted object from Proxy:`, actualObject);
logger.info(
`[CapacitorPlatformService] Extracted object from Proxy:`,
actualObject,
);
return actualObject;
}
} catch (proxyError) {
logger.error(`[CapacitorPlatformService] Failed to extract from Proxy at index ${index}:`, proxyError);
logger.error(
`[CapacitorPlatformService] Failed to extract from Proxy at index ${index}:`,
proxyError,
);
// FALLBACK: Try to extract primitive values manually
if (Array.isArray(param)) {
try {
@@ -248,30 +275,42 @@ 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);
logger.info(
`[CapacitorPlatformService] Fallback array extraction successful:`,
fallbackArray,
);
return fallbackArray;
} catch (fallbackError) {
logger.error(`[CapacitorPlatformService] Fallback array extraction failed:`, fallbackError);
logger.error(
`[CapacitorPlatformService] Fallback array extraction failed:`,
fallbackError,
);
return `[Proxy Array - Could not extract]`;
}
}
return `[Proxy Object - Could not extract]`;
}
}
try {
// Safely convert objects and arrays to JSON strings
return JSON.stringify(param);
} catch (error) {
// Handle non-serializable objects
logger.error(`[CapacitorPlatformService] Failed to serialize parameter at index ${index}:`, error);
logger.error(`[CapacitorPlatformService] Problematic parameter:`, param);
logger.error(
`[CapacitorPlatformService] Failed to serialize parameter at index ${index}:`,
error,
);
logger.error(
`[CapacitorPlatformService] Problematic parameter:`,
param,
);
// Fallback: Convert to string representation
if (Array.isArray(param)) {
return `[Array(${param.length})]`;
}
return `[Object ${param.constructor?.name || 'Unknown'}]`;
return `[Object ${param.constructor?.name || "Unknown"}]`;
}
}
if (typeof param === "boolean") {
@@ -280,12 +319,16 @@ export class CapacitorPlatformService implements PlatformService {
}
if (typeof param === "function") {
// Functions can't be serialized - convert to string representation
logger.warn(`[CapacitorPlatformService] Function parameter detected and converted to string at index ${index}`);
return `[Function ${param.name || 'Anonymous'}]`;
logger.warn(
`[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(`[CapacitorPlatformService] Symbol parameter detected and converted to string at index ${index}`);
logger.warn(
`[CapacitorPlatformService] Symbol parameter detected and converted to string at index ${index}`,
);
return param.toString();
}
// Numbers, strings, bigints are supported, but ensure bigints are converted to strings
@@ -296,13 +339,16 @@ export class CapacitorPlatformService implements PlatformService {
});
// Log converted parameters for debugging (HIGH PRIORITY)
logger.warn(`[CapacitorPlatformService] Converted params:`, convertedParams);
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
const plainParams = JSON.parse(JSON.stringify(convertedParams));
// Step 2: Create operation object using Object.create(null) for no prototype
const operation = Object.create(null) as QueuedOperation;
operation.type = type;
@@ -310,16 +356,25 @@ export class CapacitorPlatformService implements PlatformService {
operation.params = plainParams;
operation.resolve = (value: unknown) => resolve(value as R);
operation.reject = reject;
// Step 3: Freeze everything to prevent modification
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);
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
@@ -367,33 +422,42 @@ export class CapacitorPlatformService implements PlatformService {
try {
// Method 1: Check toString representation
const objString = obj.toString();
if (objString.includes('Proxy(') || objString.startsWith('Proxy')) {
logger.debug("[CapacitorPlatformService] Proxy detected via toString:", objString);
if (objString.includes("Proxy(") || objString.startsWith("Proxy")) {
logger.debug(
"[CapacitorPlatformService] Proxy detected via toString:",
objString,
);
return true;
}
// Method 2: Check constructor name
const constructorName = obj.constructor?.name;
if (constructorName === 'Proxy') {
logger.debug("[CapacitorPlatformService] Proxy detected via constructor name");
if (constructorName === "Proxy") {
logger.debug(
"[CapacitorPlatformService] Proxy detected via constructor name",
);
return true;
}
// Method 3: Check Object.prototype.toString
const objToString = Object.prototype.toString.call(obj);
if (objToString.includes('Proxy')) {
logger.debug("[CapacitorPlatformService] Proxy detected via Object.prototype.toString");
if (objToString.includes("Proxy")) {
logger.debug(
"[CapacitorPlatformService] Proxy detected via Object.prototype.toString",
);
return true;
}
// Method 4: Vue/Reactive Proxy detection - check for __v_ properties
if (typeof obj === 'object' && obj !== null) {
if (typeof obj === "object" && obj !== null) {
// Check for Vue reactive proxy indicators
const hasVueProxy = Object.getOwnPropertyNames(obj).some(prop =>
prop.startsWith('__v_') || prop.startsWith('__r_')
const hasVueProxy = Object.getOwnPropertyNames(obj).some(
(prop) => prop.startsWith("__v_") || prop.startsWith("__r_"),
);
if (hasVueProxy) {
logger.debug("[CapacitorPlatformService] Vue reactive Proxy detected");
logger.debug(
"[CapacitorPlatformService] Vue reactive Proxy detected",
);
return true;
}
}
@@ -401,15 +465,24 @@ export class CapacitorPlatformService implements PlatformService {
// Method 5: Try JSON.stringify and check for Proxy in error or result
try {
const jsonString = JSON.stringify(obj);
if (jsonString.includes('Proxy')) {
logger.debug("[CapacitorPlatformService] Proxy detected in JSON serialization");
if (jsonString.includes("Proxy")) {
logger.debug(
"[CapacitorPlatformService] Proxy detected in JSON serialization",
);
return true;
}
} catch (jsonError) {
// If JSON.stringify fails, it might be a non-serializable Proxy
const errorMessage = jsonError instanceof Error ? jsonError.message : String(jsonError);
if (errorMessage.includes('Proxy') || errorMessage.includes('circular') || errorMessage.includes('clone')) {
logger.debug("[CapacitorPlatformService] Proxy detected via JSON serialization error");
const errorMessage =
jsonError instanceof Error ? jsonError.message : String(jsonError);
if (
errorMessage.includes("Proxy") ||
errorMessage.includes("circular") ||
errorMessage.includes("clone")
) {
logger.debug(
"[CapacitorPlatformService] Proxy detected via JSON serialization error",
);
return true;
}
}
@@ -417,7 +490,10 @@ export class CapacitorPlatformService implements PlatformService {
return false;
} catch (error) {
// If we can't inspect the object, it might be a Proxy causing issues
logger.warn("[CapacitorPlatformService] Could not inspect object for Proxy detection:", error);
logger.warn(
"[CapacitorPlatformService] Could not inspect object for Proxy detection:",
error,
);
return true; // Assume it's a Proxy if we can't inspect it
}
}
@@ -1268,8 +1344,12 @@ export class CapacitorPlatformService implements PlatformService {
params?: unknown[],
): Promise<unknown[] | undefined> {
await this.waitForInitialization();
const result = await this.queueOperation<QueryExecResult>("query", sql, params || []);
const result = await this.queueOperation<QueryExecResult>(
"query",
sql,
params || [],
);
// Return the first row from the result, or undefined if no results
if (result && result.values && result.values.length > 0) {
return result.values[0];