WIP: BROKEN FOR ELECTRON: Fixes in progress

This commit is contained in:
Matthew Raymer
2025-05-28 13:09:51 +00:00
parent 25b269bbfc
commit 473a115841
20 changed files with 671 additions and 615 deletions

View File

@@ -127,10 +127,7 @@ export async function registerMigrations(): Promise<void> {
}
export async function runMigrations(
sqlExec: (
sql: string,
params?: unknown[],
) => Promise<Array<QueryExecResult>>,
sqlExec: (sql: string, params?: unknown[]) => Promise<Array<QueryExecResult>>,
): Promise<void> {
await registerMigrations();
await migrationService.runMigrations(sqlExec);

View File

@@ -123,35 +123,77 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
}
}
/**
* Logs a message to the database with proper handling of concurrent writes
* @param message - The message to log
* @author Matthew Raymer
*/
export async function logToDb(message: string): Promise<void> {
const platform = PlatformServiceFactory.getInstance();
const todayKey = new Date().toDateString();
const fullMessage = `${new Date().toISOString()} ${message}`;
// Check if we have any logs for today
const result = await platform.dbQuery(
"SELECT message FROM logs WHERE date = ?",
[todayKey],
);
try {
// Try to insert first, if it fails due to UNIQUE constraint, update instead
try {
await platform.dbExec("INSERT INTO logs (date, message) VALUES (?, ?)", [
todayKey,
fullMessage,
]);
} catch (error) {
// If insert fails due to UNIQUE constraint, update instead
if (
error instanceof Error &&
error.message.includes("UNIQUE constraint failed")
) {
const result = await platform.dbQuery(
"SELECT message FROM logs WHERE date = ?",
[todayKey],
);
if (!result || result.values.length === 0) {
// If no logs for today, clear all previous logs
await platform.dbExec("DELETE FROM logs");
if (result && result.values.length > 0) {
const prevMessages = result.values[0][0] as string;
const updatedMessage = `${prevMessages}\n${fullMessage}`;
// Insert new log
const fullMessage = `${new Date().toISOString()} ${message}`;
await platform.dbExec("INSERT INTO logs (date, message) VALUES (?, ?)", [
todayKey,
fullMessage,
]);
} else {
// Append to existing log
const prevMessages = result.values[0][0] as string;
const fullMessage = `${prevMessages}\n${new Date().toISOString()} ${message}`;
await platform.dbExec("UPDATE logs SET message = ? WHERE date = ?", [
updatedMessage,
todayKey,
]);
}
} else {
// If it's a different error, rethrow it
throw error;
}
}
await platform.dbExec("UPDATE logs SET message = ? WHERE date = ?", [
fullMessage,
todayKey,
]);
// Clean up old logs (keep only last 7 days) - do this less frequently
// Only clean up if the date is different from the last cleanup
const lastCleanupKey = "last_log_cleanup";
const result = await platform.dbQuery(
"SELECT value FROM settings WHERE key = ?",
[lastCleanupKey],
);
const lastCleanup = result?.values[0]?.[0] as string;
if (!lastCleanup || lastCleanup !== todayKey) {
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
await platform.dbExec("DELETE FROM logs WHERE date < ?", [
sevenDaysAgo.toDateString(),
]);
// Update last cleanup date
await platform.dbExec(
"INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)",
[lastCleanupKey, todayKey],
);
}
} catch (error) {
// Log to console as fallback
// eslint-disable-next-line no-console
console.error("Failed to log to database:", error);
// eslint-disable-next-line no-console
console.error("Original message:", message);
}
}

View File

@@ -2,24 +2,33 @@ const { contextBridge, ipcRenderer } = require("electron");
const logger = {
log: (message, ...args) => {
// Always log in development, log with context in production
if (process.env.NODE_ENV !== "production") {
/* eslint-disable no-console */
console.log(message, ...args);
console.log(`[Preload] ${message}`, ...args);
/* eslint-enable no-console */
}
},
warn: (message, ...args) => {
if (process.env.NODE_ENV !== "production") {
/* eslint-disable no-console */
console.warn(message, ...args);
/* eslint-enable no-console */
}
// Always log warnings
/* eslint-disable no-console */
console.warn(`[Preload] ${message}`, ...args);
/* eslint-enable no-console */
},
error: (message, ...args) => {
// Always log errors
/* eslint-disable no-console */
console.error(message, ...args); // Errors should always be logged
console.error(`[Preload] ${message}`, ...args);
/* eslint-enable no-console */
},
info: (message, ...args) => {
// Always log info in development, log with context in production
if (process.env.NODE_ENV !== "production") {
/* eslint-disable no-console */
console.info(`[Preload] ${message}`, ...args);
/* eslint-enable no-console */
}
},
};
// Use a more direct path resolution approach
@@ -41,7 +50,10 @@ const getPath = (pathType) => {
}
};
logger.log("Preload script starting...");
logger.info("Preload script starting...");
// Force electron platform in the renderer process
window.process = { env: { VITE_PLATFORM: "electron" } };
try {
contextBridge.exposeInMainWorld("electronAPI", {
@@ -65,6 +77,7 @@ try {
env: {
isElectron: true,
isDev: process.env.NODE_ENV === "development",
platform: "electron", // Explicitly set platform
},
// Path utilities
getBasePath: () => {
@@ -72,7 +85,7 @@ try {
},
});
logger.log("Preload script completed successfully");
logger.info("Preload script completed successfully");
} catch (error) {
logger.error("Error in preload script:", error);
}

View File

@@ -43,14 +43,14 @@ export interface KeyMeta {
derivationPath: string;
registered?: boolean;
profileImageUrl?: string;
identity?: string; // Stringified IIdentifier object from Veramo
passkeyCredIdHex?: string; // The Webauthn credential ID in hex, if this is from a passkey
identity?: string; // Stringified IIdentifier object from Veramo
passkeyCredIdHex?: string; // The Webauthn credential ID in hex, if this is from a passkey
[key: string]: unknown;
}
export interface QuantitativeValue extends GenericVerifiableCredential {
'@type': 'QuantitativeValue';
'@context': string | string[];
"@type": "QuantitativeValue";
"@context": string | string[];
amountOfThisGood: number;
unitCode: string;
[key: string]: unknown;
@@ -101,10 +101,10 @@ export interface Agent {
}
export interface ClaimObject {
'@type': string;
'@context'?: string | string[];
"@type": string;
"@context"?: string | string[];
fulfills?: Array<{
'@type': string;
"@type": string;
identifier?: string;
[key: string]: unknown;
}>;
@@ -119,16 +119,16 @@ export interface ClaimObject {
}
export interface VerifiableCredentialClaim {
'@context': string | string[];
'@type': string;
"@context": string | string[];
"@type": string;
type: string[];
credentialSubject: ClaimObject;
[key: string]: unknown;
}
export interface GiveVerifiableCredential extends GenericVerifiableCredential {
'@type': 'GiveAction';
'@context': string | string[];
"@type": "GiveAction";
"@context": string | string[];
object?: GenericVerifiableCredential;
agent?: Agent;
participant?: {
@@ -136,7 +136,7 @@ export interface GiveVerifiableCredential extends GenericVerifiableCredential {
[key: string]: unknown;
};
fulfills?: Array<{
'@type': string;
"@type": string;
identifier?: string;
[key: string]: unknown;
}>;
@@ -144,8 +144,8 @@ export interface GiveVerifiableCredential extends GenericVerifiableCredential {
}
export interface OfferVerifiableCredential extends GenericVerifiableCredential {
'@type': 'OfferAction';
'@context': string | string[];
"@type": "OfferAction";
"@context": string | string[];
object?: GenericVerifiableCredential;
agent?: Agent;
participant?: {
@@ -155,7 +155,7 @@ export interface OfferVerifiableCredential extends GenericVerifiableCredential {
itemOffered?: {
description?: string;
isPartOf?: {
'@type': string;
"@type": string;
identifier: string;
[key: string]: unknown;
};
@@ -164,9 +164,10 @@ export interface OfferVerifiableCredential extends GenericVerifiableCredential {
[key: string]: unknown;
}
export interface RegisterVerifiableCredential extends GenericVerifiableCredential {
'@type': 'RegisterAction';
'@context': string | string[];
export interface RegisterVerifiableCredential
extends GenericVerifiableCredential {
"@type": "RegisterAction";
"@context": string | string[];
agent: {
identifier: string;
};

View File

@@ -194,7 +194,9 @@ export class PeerSetup {
},
};
const credential = await navigator.credentials.get(options) as PublicKeyCredential;
const credential = (await navigator.credentials.get(
options,
)) as PublicKeyCredential;
// console.log("nav credential get", credential);
const response = credential?.response as AuthenticatorAssertionResponse;
@@ -229,9 +231,7 @@ export class PeerSetup {
.replace(/\//g, "_")
.replace(/=+$/, "");
const origSignature = Buffer.from(response?.signature).toString(
"base64",
);
const origSignature = Buffer.from(response?.signature).toString("base64");
this.signature = origSignature
.replace(/\+/g, "-")
.replace(/\//g, "_")
@@ -327,10 +327,7 @@ export async function verifyJwtP256(
const publicKeyBytes = peerDidToPublicKeyBytes(issuerDid);
// Use challenge in preimage construction
const preimage = Buffer.concat([
authDataFromBase,
Buffer.from(challenge),
]);
const preimage = Buffer.concat([authDataFromBase, Buffer.from(challenge)]);
const isValid = p256.verify(
finalSigBuffer,
@@ -391,10 +388,7 @@ export async function verifyJwtWebCrypto(
const finalSigBuffer = unwrapEC2Signature(sigBuffer);
// Use challenge in preimage construction
const preimage = Buffer.concat([
authDataFromBase,
Buffer.from(challenge),
]);
const preimage = Buffer.concat([authDataFromBase, Buffer.from(challenge)]);
return verifyPeerSignature(preimage, issuerDid, finalSigBuffer);
}

View File

@@ -53,7 +53,7 @@ import {
ClaimObject,
VerifiableCredentialClaim,
Agent,
QuantitativeValue
QuantitativeValue,
} from "../interfaces/common";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@@ -106,11 +106,12 @@ export const CONTACT_CONFIRM_URL_PATH_TIME_SAFARI = "/contact/confirm/";
*/
export const ENDORSER_CH_HANDLE_PREFIX = "https://endorser.ch/entity/";
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper<GenericVerifiableCredential> = {
claim: {
"@context": SCHEMA_ORG_CONTEXT,
"@type": ""
},
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper<GenericVerifiableCredential> =
{
claim: {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "",
},
handleId: "",
id: "",
issuedAt: "",
@@ -200,10 +201,10 @@ const testRecursivelyOnStrings = (
return input.some((item) => testRecursivelyOnStrings(item, test));
} else if (input && typeof input === "object") {
return Object.values(input as Record<string, unknown>).some((value) =>
testRecursivelyOnStrings(value, test)
testRecursivelyOnStrings(value, test),
);
}
return false;
}
return false;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -545,7 +546,7 @@ export async function setPlanInCache(
* @returns {string|undefined} User-friendly message or undefined if none found
*/
export function serverMessageForUser(error: unknown): string | undefined {
if (error && typeof error === 'object' && 'response' in error) {
if (error && typeof error === "object" && "response" in error) {
const err = error as AxiosErrorResponse;
return err.response?.data?.error?.message;
}
@@ -571,21 +572,26 @@ export function errorStringForLog(error: unknown) {
// --- property '_value' closes the circle
}
let fullError = "" + error + " - JSON: " + stringifiedError;
if (error && typeof error === 'object' && 'response' in error) {
if (error && typeof error === "object" && "response" in error) {
const err = error as AxiosErrorResponse;
const errorResponseText = JSON.stringify(err.response);
// for some reason, error.response is not included in stringify result (eg. for 400 errors on invite redemptions)
if (!R.empty(errorResponseText) && !fullError.includes(errorResponseText)) {
// add error.response stuff
if (err.response?.config && err.config && R.equals(err.config, err.response.config)) {
// but exclude "config" because it's already in there
const newErrorResponseText = JSON.stringify(
// for some reason, error.response is not included in stringify result (eg. for 400 errors on invite redemptions)
if (!R.empty(errorResponseText) && !fullError.includes(errorResponseText)) {
// add error.response stuff
if (
err.response?.config &&
err.config &&
R.equals(err.config, err.response.config)
) {
// but exclude "config" because it's already in there
const newErrorResponseText = JSON.stringify(
R.omit(["config"] as never[], err.response),
);
fullError += " - .response w/o same config JSON: " + newErrorResponseText;
} else {
fullError += " - .response JSON: " + errorResponseText;
);
fullError +=
" - .response w/o same config JSON: " + newErrorResponseText;
} else {
fullError += " - .response JSON: " + errorResponseText;
}
}
}
@@ -664,7 +670,7 @@ export function hydrateGive(
"@type": "GiveAction",
object: undefined,
agent: undefined,
fulfills: []
fulfills: [],
};
if (lastClaimId) {
@@ -679,13 +685,13 @@ export function hydrateGive(
vcClaim.recipient = { identifier: toDid };
}
vcClaim.description = description || undefined;
if (amount && !isNaN(amount)) {
const quantitativeValue: QuantitativeValue = {
"@context": SCHEMA_ORG_CONTEXT,
"@type": "QuantitativeValue",
amountOfThisGood: amount,
unitCode: unitCode || "HUR"
unitCode: unitCode || "HUR",
};
vcClaim.object = quantitativeValue;
}
@@ -697,34 +703,34 @@ export function hydrateGive(
// Filter and add fulfills elements
vcClaim.fulfills = vcClaim.fulfills.filter(
(elem: { '@type': string }) => elem["@type"] !== "PlanAction"
(elem: { "@type": string }) => elem["@type"] !== "PlanAction",
);
if (fulfillsProjectHandleId) {
vcClaim.fulfills.push({
"@type": "PlanAction",
identifier: fulfillsProjectHandleId
identifier: fulfillsProjectHandleId,
});
}
vcClaim.fulfills = vcClaim.fulfills.filter(
(elem: { '@type': string }) => elem["@type"] !== "Offer"
(elem: { "@type": string }) => elem["@type"] !== "Offer",
);
if (fulfillsOfferHandleId) {
vcClaim.fulfills.push({
"@type": "Offer",
identifier: fulfillsOfferHandleId
identifier: fulfillsOfferHandleId,
});
}
vcClaim.fulfills = vcClaim.fulfills.filter(
(elem: { '@type': string }) =>
elem["@type"] !== "DonateAction" && elem["@type"] !== "TradeAction"
(elem: { "@type": string }) =>
elem["@type"] !== "DonateAction" && elem["@type"] !== "TradeAction",
);
vcClaim.fulfills.push({
"@type": isTrade ? "TradeAction" : "DonateAction"
vcClaim.fulfills.push({
"@type": isTrade ? "TradeAction" : "DonateAction",
});
vcClaim.image = imageUrl || undefined;
@@ -732,7 +738,7 @@ export function hydrateGive(
if (providerPlanHandleId) {
vcClaim.provider = {
"@type": "PlanAction",
identifier: providerPlanHandleId
identifier: providerPlanHandleId,
};
}
@@ -854,7 +860,7 @@ export function hydrateOffer(
"@type": "OfferAction",
object: undefined,
agent: undefined,
itemOffered: {}
itemOffered: {},
};
if (lastClaimId) {
@@ -875,7 +881,7 @@ export function hydrateOffer(
"@context": SCHEMA_ORG_CONTEXT,
"@type": "QuantitativeValue",
amountOfThisGood: amount,
unitCode: unitCode || "HUR"
unitCode: unitCode || "HUR",
};
vcClaim.object = quantitativeValue;
}
@@ -886,7 +892,7 @@ export function hydrateOffer(
if (fulfillsProjectHandleId) {
vcClaim.itemOffered.isPartOf = {
"@type": "PlanAction",
identifier: fulfillsProjectHandleId
identifier: fulfillsProjectHandleId,
};
}
}
@@ -1024,12 +1030,14 @@ export async function createAndSubmitClaim(
logger.error("Error submitting claim:", error);
const errorMessage: string =
serverMessageForUser(error) ||
(error && typeof error === 'object' && 'message' in error ? String(error.message) : undefined) ||
(error && typeof error === "object" && "message" in error
? String(error.message)
: undefined) ||
"Got some error submitting the claim. Check your permissions, network, and error logs.";
return {
success: false,
error: errorMessage
error: errorMessage,
};
}
}
@@ -1061,10 +1069,7 @@ export async function generateEndorserJwtUrlForAccount(
// Add the next key -- not recommended for the QR code for such a high resolution
if (isContact) {
const newDerivPath = nextDerivationPath(account.derivationPath);
const nextPublicHex = deriveAddress(
account.mnemonic,
newDerivPath,
)[2];
const nextPublicHex = deriveAddress(account.mnemonic, newDerivPath)[2];
const nextPublicEncKey = Buffer.from(nextPublicHex, "hex");
const nextPublicEncKeyHash = sha256(nextPublicEncKey);
const nextPublicEncKeyHashBase64 =
@@ -1133,13 +1138,15 @@ export const capitalizeAndInsertSpacesBeforeCaps = (text: string) => {
similar code is also contained in endorser-mobile
**/
const claimSummary = (
claim: GenericVerifiableCredential | GenericCredWrapper<GenericVerifiableCredential>,
claim:
| GenericVerifiableCredential
| GenericCredWrapper<GenericVerifiableCredential>,
) => {
if (!claim) {
return "something";
}
let specificClaim: GenericVerifiableCredential;
if ('claim' in claim) {
if ("claim" in claim) {
// It's a GenericCredWrapper
specificClaim = claim.claim as GenericVerifiableCredential;
} else {
@@ -1180,7 +1187,7 @@ export const claimSpecialDescription = (
contacts: Array<Contact>,
) => {
let claim = record.claim;
if ('claim' in claim) {
if ("claim" in claim) {
claim = claim.claim as GenericVerifiableCredential;
}
@@ -1189,12 +1196,23 @@ export const claimSpecialDescription = (
const type = claimObj["@type"] || "UnknownType";
if (type === "AgreeAction") {
return issuer + " agreed with " + claimSummary(claimObj.object as GenericVerifiableCredential);
return (
issuer +
" agreed with " +
claimSummary(claimObj.object as GenericVerifiableCredential)
);
} else if (isAccept(claim)) {
return issuer + " accepted " + claimSummary(claimObj.object as GenericVerifiableCredential);
return (
issuer +
" accepted " +
claimSummary(claimObj.object as GenericVerifiableCredential)
);
} else if (type === "GiveAction") {
const giveClaim = claim as GiveVerifiableCredential;
const agent: Agent = giveClaim.agent || { identifier: undefined, did: undefined };
const agent: Agent = giveClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
@@ -1209,7 +1227,10 @@ export const claimSpecialDescription = (
return contactInfo + " gave" + offering + recipientInfo;
} else if (type === "JoinAction") {
const joinClaim = claim as ClaimObject;
const agent: Agent = joinClaim.agent || { identifier: undefined, did: undefined };
const agent: Agent = joinClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
@@ -1219,7 +1240,10 @@ export const claimSpecialDescription = (
return contactInfo + " joined" + objectInfo;
} else if (isOffer(claim)) {
const offerClaim = claim as OfferVerifiableCredential;
const agent: Agent = offerClaim.agent || { identifier: undefined, did: undefined };
const agent: Agent = offerClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
@@ -1234,7 +1258,10 @@ export const claimSpecialDescription = (
return contactInfo + " offered" + offering + offerRecipientInfo;
} else if (type === "PlanAction") {
const planClaim = claim as ClaimObject;
const agent: Agent = planClaim.agent || { identifier: undefined, did: undefined };
const agent: Agent = planClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
@@ -1244,7 +1271,10 @@ export const claimSpecialDescription = (
return contactInfo + " planned" + objectInfo;
} else if (type === "Tenure") {
const tenureClaim = claim as ClaimObject;
const agent: Agent = tenureClaim.agent || { identifier: undefined, did: undefined };
const agent: Agent = tenureClaim.agent || {
identifier: undefined,
did: undefined,
};
const agentDid = agent.did || agent.identifier;
const contactInfo = agentDid
? didInfo(agentDid, activeDid, identifiers, contacts)
@@ -1253,11 +1283,7 @@ export const claimSpecialDescription = (
const objectInfo = object ? " " + claimSummary(object) : "";
return contactInfo + " has tenure" + objectInfo;
} else {
return (
issuer +
" declared " +
claimSummary(claim)
);
return issuer + " declared " + claimSummary(claim);
}
};
@@ -1333,35 +1359,39 @@ export async function register(
contact: Contact,
): Promise<{ success?: boolean; error?: string }> {
try {
const vcJwt = await createInviteJwt(activeDid, contact);
const url = apiServer + "/api/v2/claim";
const resp = await axios.post<{
success?: {
handleId?: string;
const vcJwt = await createInviteJwt(activeDid, contact);
const url = apiServer + "/api/v2/claim";
const resp = await axios.post<{
success?: {
handleId?: string;
embeddedRecordError?: string;
};
error?: string;
message?: string;
}>(url, { jwtEncoded: vcJwt });
if (resp.data?.success?.handleId) {
return { success: true };
} else if (resp.data?.success?.embeddedRecordError) {
let message = "There was some problem with the registration and so it may not be complete.";
if (resp.data?.success?.handleId) {
return { success: true };
} else if (resp.data?.success?.embeddedRecordError) {
let message =
"There was some problem with the registration and so it may not be complete.";
if (typeof resp.data.success.embeddedRecordError === "string") {
message += " " + resp.data.success.embeddedRecordError;
}
return { error: message };
} else {
message += " " + resp.data.success.embeddedRecordError;
}
return { error: message };
} else {
logger.error("Registration error:", JSON.stringify(resp.data));
return { error: "Got a server error when registering." };
}
} catch (error: unknown) {
if (error && typeof error === 'object') {
if (error && typeof error === "object") {
const err = error as AxiosErrorResponse;
const errorMessage = err.message ||
(err.response?.data && typeof err.response.data === 'object' && 'message' in err.response.data
? (err.response.data as { message: string }).message
const errorMessage =
err.message ||
(err.response?.data &&
typeof err.response.data === "object" &&
"message" in err.response.data
? (err.response.data as { message: string }).message
: undefined);
logger.error("Registration error:", errorMessage || JSON.stringify(err));
return { error: errorMessage || "Got a server error when registering." };

View File

@@ -30,19 +30,13 @@ import {
simpleEncrypt,
} from "../libs/crypto";
import * as serverUtil from "../libs/endorserServer";
import {
containsHiddenDid,
} from "../libs/endorserServer";
import { containsHiddenDid } from "../libs/endorserServer";
import {
GenericCredWrapper,
GenericVerifiableCredential,
} from "../interfaces/common";
import {
GiveSummaryRecord,
} from "../interfaces/records";
import {
OfferVerifiableCredential,
} from "../interfaces/claims";
import { GiveSummaryRecord } from "../interfaces/records";
import { OfferVerifiableCredential } from "../interfaces/claims";
import { KeyMeta } from "../interfaces/common";
import { createPeerDid } from "../libs/crypto/vc/didPeer";
import { registerCredential } from "../libs/crypto/vc/passkeyDidPeer";
@@ -406,10 +400,7 @@ export function offerGiverDid(
export const canFulfillOffer = (
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
) => {
return (
veriClaim.claimType === "Offer" &&
!!offerGiverDid(veriClaim)
);
return veriClaim.claimType === "Offer" && !!offerGiverDid(veriClaim);
};
// return object with paths and arrays of DIDs for any keys ending in "VisibleToDid"
@@ -478,8 +469,10 @@ export function findAllVisibleToDids(
*
**/
export interface AccountKeyInfo extends Omit<Account, 'derivationPath'>, Omit<KeyMeta, 'derivationPath'> {
derivationPath?: string; // Make it optional to match Account type
export interface AccountKeyInfo
extends Omit<Account, "derivationPath">,
Omit<KeyMeta, "derivationPath"> {
derivationPath?: string; // Make it optional to match Account type
}
export const retrieveAccountCount = async (): Promise<number> => {
@@ -489,7 +482,7 @@ export const retrieveAccountCount = async (): Promise<number> => {
`SELECT COUNT(*) FROM accounts`,
);
if (dbResult?.values?.[0]?.[0]) {
result = dbResult.values[0][0] as number;
result = dbResult.values[0][0] as number;
}
if (USE_DEXIE_DB) {
@@ -638,7 +631,7 @@ export const retrieveAllFullyDecryptedAccounts = async (): Promise<
) as unknown as AccountEncrypted[];
if (USE_DEXIE_DB) {
const accountsDB = await accountsDBPromise;
allAccounts = await accountsDB.accounts.toArray() as AccountEncrypted[];
allAccounts = (await accountsDB.accounts.toArray()) as AccountEncrypted[];
}
return allAccounts;
};

View File

@@ -10,6 +10,12 @@ import { FontAwesomeIcon } from "./libs/fontawesome";
import Camera from "simple-vue-camera";
import { logger } from "./utils/logger";
const platform = process.env.VITE_PLATFORM;
const pwa_enabled = process.env.VITE_PWA_ENABLED === "true";
logger.error("Platform", { platform });
logger.error("PWA enabled", { pwa_enabled });
// Global Error Handler
function setupGlobalErrorHandler(app: VueApp) {
logger.log("[App Init] Setting up global error handler");

View File

@@ -1,4 +1,16 @@
import { initializeApp } from "./main.common";
import { logger } from "./utils/logger";
const platform = process.env.VITE_PLATFORM;
const pwa_enabled = process.env.VITE_PWA_ENABLED === "true";
logger.info("[Electron] Initializing app");
logger.info("[Electron] Platform:", { platform });
logger.info("[Electron] PWA enabled:", { pwa_enabled });
if (pwa_enabled) {
logger.warn("[Electron] PWA is enabled, but not supported in electron");
}
const app = initializeApp();
app.mount("#app");

View File

@@ -1,11 +1,15 @@
import { initBackend } from "absurd-sql/dist/indexeddb-main-thread";
import { initializeApp } from "./main.common";
import { logger } from "./utils/logger";
const platform = process.env.VITE_PLATFORM;
const pwa_enabled = process.env.VITE_PWA_ENABLED === "true";
logger.error("[Web] PWA enabled", { pwa_enabled });
logger.error("[Web] Platform", { platform });
// Only import service worker for web builds
if (
process.env.VITE_PLATFORM !== "electron" &&
process.env.VITE_PWA_ENABLED === "true"
) {
if (platform !== "electron" && pwa_enabled) {
import("./registerServiceWorker"); // Web PWA support
}
@@ -24,6 +28,10 @@ function sqlInit() {
// workers through the main thread
initBackend(worker);
}
sqlInit();
if (platform === "web" || platform === "development") {
sqlInit();
} else {
logger.info("[Web] SQL not initialized for platform", { platform });
}
app.mount("#app");

View File

@@ -22,12 +22,12 @@ interface AbsurdSqlDatabase {
) => Promise<{ changes: number; lastId?: number }>;
}
class AbsurdSqlDatabaseService implements DatabaseService {
class AbsurdSqlDatabaseService<T> implements DatabaseService {
private static instance: AbsurdSqlDatabaseService | null = null;
private db: AbsurdSqlDatabase | null;
private initialized: boolean;
private initializationPromise: Promise<void> | null = null;
private operationQueue: Array<QueuedOperation<any>> = [];
private operationQueue: Array<QueuedOperation<T>> = [];
private isProcessingQueue: boolean = false;
private constructor() {

View File

@@ -4,7 +4,13 @@ import {
StartScanOptions,
LensFacing,
} from "@capacitor-mlkit/barcode-scanning";
import { QRScannerService, ScanListener, QRScannerOptions, CameraStateListener, CameraState } from "./types";
import {
QRScannerService,
ScanListener,
QRScannerOptions,
CameraStateListener,
CameraState,
} from "./types";
import { logger } from "@/utils/logger";
export class CapacitorQRScanner implements QRScannerService {
@@ -96,7 +102,10 @@ export class CapacitorQRScanner implements QRScannerService {
// Check if scanning is supported
if (!(await this.isSupported())) {
this.updateCameraState("error", "QR scanning not supported on this device");
this.updateCameraState(
"error",
"QR scanning not supported on this device",
);
throw new Error("QR scanning not supported on this device");
}

View File

@@ -512,7 +512,10 @@ export class WebInlineQRScanner implements QRScannerService {
this.scanAttempts = 0;
this.lastScanTime = Date.now();
this.updateCameraState("initializing", "Starting camera...");
logger.error(`[WebInlineQRScanner:${this.id}] Starting scan with options:`, this.options);
logger.error(
`[WebInlineQRScanner:${this.id}] Starting scan with options:`,
this.options,
);
// Get camera stream with options
logger.error(

View File

@@ -121,10 +121,10 @@ export class DeepLinkHandler {
// Validate route exists before proceeding
if (!this.ROUTE_MAP[routePath]) {
throw {
code: "INVALID_ROUTE",
throw {
code: "INVALID_ROUTE",
message: `Invalid route path: ${routePath}`,
details: { routePath }
details: { routePath },
};
}

View File

@@ -42,7 +42,8 @@ export const logger = {
info: (message: string, ...args: unknown[]) => {
if (
process.env.NODE_ENV !== "production" ||
process.env.VITE_PLATFORM === "capacitor"
process.env.VITE_PLATFORM === "capacitor" ||
process.env.VITE_PLATFORM === "electron"
) {
// eslint-disable-next-line no-console
console.info(message, ...args);
@@ -53,7 +54,8 @@ export const logger = {
warn: (message: string, ...args: unknown[]) => {
if (
process.env.NODE_ENV !== "production" ||
process.env.VITE_PLATFORM === "capacitor"
process.env.VITE_PLATFORM === "capacitor" ||
process.env.VITE_PLATFORM === "electron"
) {
// eslint-disable-next-line no-console
console.warn(message, ...args);

View File

@@ -995,8 +995,8 @@ export default class ContactsView extends Vue {
newContact as unknown as Record<string, unknown>,
"contacts",
);
console.log("sql", sql);
console.log("params", params);
logger.error("sql", sql);
logger.error("params", params);
let contactPromise = platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
// @ts-expect-error since the result of this promise won't be used, and this will go away soon

View File

@@ -90,15 +90,12 @@ import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
import * as databaseUtil from "../db/databaseUtil";
import {
accountsDBPromise,
db,
retrieveSettingsForActiveAccount,
} from "../db/index";
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
import {
DEFAULT_ROOT_DERIVATION_PATH,
deriveAddress,
newIdentifier,
simpleEncrypt,
} from "../libs/crypto";
import { retrieveAccountCount, saveNewIdentity } from "../libs/util";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";