forked from trent_larson/crowd-funder-for-time-pwa
WIP: certificate view and dependency updates
- Update certificate view canvas rendering and QR code generation - Upgrade dependencies (expo-file-system, expo-font, expo-keep-awake) - Fix type imports for nostr-tools and dexie-export-import - Update vite config for better dependency resolution - Clean up main entry points (capacitor, electron, pywebview) - Improve error handling in API and plan services - Add type safety to API error handling - Update build configuration for platform-specific builds This is a work in progress commit focusing on certificate view improvements and dependency maintenance. Some type definitions and build configurations may need further refinement.
This commit is contained in:
@@ -2,21 +2,16 @@ import { initializeApp } from "./main.common";
|
||||
import { App } from "@capacitor/app";
|
||||
import router from "./router";
|
||||
import { handleApiError } from "./services/api";
|
||||
import { loadPlanWithRetry } from "./services/plan";
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
|
||||
console.log("[Capacitor] Starting initialization");
|
||||
console.log("[Capacitor] Platform:", process.env.VITE_PLATFORM);
|
||||
|
||||
const app = initializeApp();
|
||||
|
||||
// Store initial deep link if app is not ready
|
||||
let pendingDeepLink: string | null = null;
|
||||
|
||||
// Initialize API error handling
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
window.addEventListener("unhandledrejection", (event) => {
|
||||
if (event.reason?.response) {
|
||||
handleApiError(event.reason, event.reason.config?.url || 'unknown');
|
||||
handleApiError(event.reason, event.reason.config?.url || "unknown");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,41 +20,43 @@ const handleDeepLink = async (data: { url: string }) => {
|
||||
try {
|
||||
console.log("[Capacitor Deep Link] START Handler");
|
||||
console.log("[Capacitor Deep Link] Received URL:", data.url);
|
||||
|
||||
|
||||
// Wait for router to be ready
|
||||
await router.isReady();
|
||||
|
||||
|
||||
// Parse the custom URL scheme
|
||||
const parts = data.url.split('://');
|
||||
const parts = data.url.split("://");
|
||||
if (parts.length !== 2) {
|
||||
throw new Error('Invalid URL format');
|
||||
throw new Error("Invalid URL format");
|
||||
}
|
||||
|
||||
const path = parts[1]; // This will be "claim/01JMAAFZRNSRTQ0EBSD70A8E1H"
|
||||
|
||||
const path = parts[1]; // This will be "claim/01JMAAFZRNSRTQ0EBSD70A8E1H"
|
||||
console.log("[Capacitor Deep Link] Parsed path:", path);
|
||||
|
||||
|
||||
// Map parameterized routes
|
||||
const paramRoutes = {
|
||||
'claim': /^claim\/(.+)$/, // Updated pattern without leading slash
|
||||
claim: /^claim\/(.+)$/, // Updated pattern without leading slash
|
||||
};
|
||||
|
||||
// Check if path matches any parameterized route
|
||||
for (const [routeName, pattern] of Object.entries(paramRoutes)) {
|
||||
const match = path.match(pattern);
|
||||
if (match) {
|
||||
console.log(`[Capacitor Deep Link] Matched route: ${routeName}, param: ${match[1]}`);
|
||||
await router.replace({
|
||||
console.log(
|
||||
`[Capacitor Deep Link] Matched route: ${routeName}, param: ${match[1]}`,
|
||||
);
|
||||
await router.replace({
|
||||
name: routeName,
|
||||
params: { id: match[1] }
|
||||
params: { id: match[1] },
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await router.replace('/' + path);
|
||||
await router.replace("/" + path);
|
||||
} catch (error) {
|
||||
console.error("[Capacitor Deep Link] Error:", error);
|
||||
handleApiError(error, 'deep-link');
|
||||
handleApiError(error, "deep-link");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,4 +65,4 @@ App.addListener("appUrlOpen", handleDeepLink);
|
||||
|
||||
console.log("[Capacitor] Mounting app");
|
||||
app.mount("#app");
|
||||
console.log("[Capacitor] App mounted");
|
||||
console.log("[Capacitor] App mounted");
|
||||
|
||||
@@ -15,16 +15,16 @@ function setupGlobalErrorHandler(app: VueApp) {
|
||||
app.config.errorHandler = (
|
||||
err: unknown,
|
||||
instance: ComponentPublicInstance | null,
|
||||
info: string
|
||||
info: string,
|
||||
) => {
|
||||
console.error("[App Error] Global Error Handler:", {
|
||||
error: err,
|
||||
info,
|
||||
component: instance?.$options.name || 'unknown'
|
||||
component: instance?.$options.name || "unknown",
|
||||
});
|
||||
alert(
|
||||
(err instanceof Error ? err.message : "Something bad happened") +
|
||||
" - Try reloading or restarting the app."
|
||||
" - Try reloading or restarting the app.",
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -33,24 +33,23 @@ function setupGlobalErrorHandler(app: VueApp) {
|
||||
export function initializeApp() {
|
||||
console.log("[App Init] Starting app initialization");
|
||||
console.log("[App Init] Platform:", process.env.VITE_PLATFORM);
|
||||
|
||||
|
||||
const app = createApp(App);
|
||||
console.log("[App Init] Vue app created");
|
||||
|
||||
app.component("fa", FontAwesomeIcon)
|
||||
.component("camera", Camera);
|
||||
|
||||
app.component("font-awesome", FontAwesomeIcon).component("camera", Camera);
|
||||
console.log("[App Init] Components registered");
|
||||
|
||||
|
||||
const pinia = createPinia();
|
||||
app.use(pinia);
|
||||
console.log("[App Init] Pinia store initialized");
|
||||
|
||||
|
||||
app.use(VueAxios, axios);
|
||||
console.log("[App Init] Axios initialized");
|
||||
|
||||
|
||||
app.use(router);
|
||||
console.log("[App Init] Router initialized");
|
||||
|
||||
|
||||
app.use(Notifications);
|
||||
console.log("[App Init] Notifications initialized");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { initializeApp } from "./main.common";
|
||||
|
||||
const app = initializeApp();
|
||||
app.mount("#app");
|
||||
app.mount("#app");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { initializeApp } from "./main.common";
|
||||
|
||||
const app = initializeApp();
|
||||
app.mount("#app");
|
||||
app.mount("#app");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export const handleApiError = (error: any, endpoint: string) => {
|
||||
if (process.env.VITE_PLATFORM === 'capacitor') {
|
||||
import { AxiosError } from "axios";
|
||||
|
||||
export const handleApiError = (error: AxiosError, endpoint: string) => {
|
||||
if (process.env.VITE_PLATFORM === "capacitor") {
|
||||
console.error(`[Capacitor API Error] ${endpoint}:`, {
|
||||
message: error.message,
|
||||
status: error.response?.status,
|
||||
@@ -7,16 +9,16 @@ export const handleApiError = (error: any, endpoint: string) => {
|
||||
config: {
|
||||
url: error.config?.url,
|
||||
method: error.config?.method,
|
||||
headers: error.config?.headers
|
||||
}
|
||||
headers: error.config?.headers,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Specific handling for rate limits
|
||||
if (error.response?.status === 400) {
|
||||
console.warn(`[Rate Limit] ${endpoint}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
throw error;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,71 +1,80 @@
|
||||
import axios from 'axios';
|
||||
import axios from "axios";
|
||||
|
||||
interface PlanResponse {
|
||||
data?: any;
|
||||
data?: unknown;
|
||||
status?: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const loadPlanWithRetry = async (handle: string, retries = 3): Promise<PlanResponse> => {
|
||||
export const loadPlanWithRetry = async (
|
||||
handle: string,
|
||||
retries = 3,
|
||||
): Promise<PlanResponse> => {
|
||||
try {
|
||||
console.log(`[Plan Service] Loading plan ${handle}, attempt 1/${retries}`);
|
||||
console.log(`[Plan Service] Context: Deep link handle=${handle}, isClaimFlow=${handle.includes('claim')}`);
|
||||
|
||||
console.log(
|
||||
`[Plan Service] Context: Deep link handle=${handle}, isClaimFlow=${handle.includes("claim")}`,
|
||||
);
|
||||
|
||||
// Different endpoint if this is a claim flow
|
||||
const response = await loadPlan(handle);
|
||||
console.log(`[Plan Service] Plan ${handle} loaded successfully:`, {
|
||||
status: response?.status,
|
||||
headers: response?.headers,
|
||||
data: response?.data
|
||||
data: response?.data,
|
||||
});
|
||||
|
||||
|
||||
return response;
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error(`[Plan Service] Error loading plan ${handle}:`, {
|
||||
message: error.message,
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
data: error.response?.data,
|
||||
headers: error.response?.headers,
|
||||
message: (error as Error).message,
|
||||
status: (error as { response?: { status?: number } })?.response?.status,
|
||||
statusText: (error as { response?: { statusText?: string } })?.response
|
||||
?.statusText,
|
||||
data: (error as { response?: { data?: unknown } })?.response?.data,
|
||||
headers: (error as { response?: { headers?: unknown } })?.response
|
||||
?.headers,
|
||||
config: {
|
||||
url: error.config?.url,
|
||||
method: error.config?.method,
|
||||
baseURL: error.config?.baseURL,
|
||||
headers: error.config?.headers
|
||||
}
|
||||
url: (error as { config?: { url?: string } })?.config?.url,
|
||||
method: (error as { config?: { method?: string } })?.config?.method,
|
||||
baseURL: (error as { config?: { baseURL?: string } })?.config?.baseURL,
|
||||
headers: (error as { config?: { headers?: unknown } })?.config?.headers,
|
||||
},
|
||||
});
|
||||
|
||||
if (retries > 1) {
|
||||
console.log(`[Plan Service] Retrying plan ${handle}, ${retries-1} attempts remaining`);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
console.log(
|
||||
`[Plan Service] Retrying plan ${handle}, ${retries - 1} attempts remaining`,
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return loadPlanWithRetry(handle, retries - 1);
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
error: `Failed to load plan ${handle} after ${4-retries} attempts: ${error.message}`,
|
||||
status: error.response?.status
|
||||
error: `Failed to load plan ${handle} after ${4 - retries} attempts: ${(error as Error).message}`,
|
||||
status: (error as { response?: { status?: number } })?.response?.status,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const loadPlan = async (handle: string): Promise<PlanResponse> => {
|
||||
console.log(`[Plan Service] Making API request for plan ${handle}`);
|
||||
|
||||
const endpoint = handle.includes('claim')
|
||||
|
||||
const endpoint = handle.includes("claim")
|
||||
? `/api/claims/${handle}`
|
||||
: `/api/plans/${handle}`;
|
||||
|
||||
|
||||
console.log(`[Plan Service] Using endpoint: ${endpoint}`);
|
||||
|
||||
|
||||
try {
|
||||
const response = await axios.get(endpoint);
|
||||
return response;
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error(`[Plan Service] API request failed for ${handle}:`, {
|
||||
endpoint,
|
||||
error: error.message,
|
||||
response: error.response?.data
|
||||
error: (error as Error).message,
|
||||
response: (error as { response?: { data?: unknown } })?.response?.data,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -895,7 +895,7 @@ import { AxiosError } from "axios";
|
||||
import { Buffer } from "buffer/";
|
||||
import Dexie from "dexie";
|
||||
import "dexie-export-import";
|
||||
import { ImportProgress } from "dexie-export-import/dist/import";
|
||||
import { importDB, ImportProgress } from "dexie-export-import";
|
||||
import { LeafletMouseEvent } from "leaflet";
|
||||
import * as R from "ramda";
|
||||
import { IIdentifier } from "@veramo/core";
|
||||
|
||||
@@ -229,9 +229,7 @@
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { AxiosError, AxiosRequestHeaders } from "axios";
|
||||
import { DateTime } from "luxon";
|
||||
import { finalizeEvent, serializeEvent } from "nostr-tools";
|
||||
// these core imports could also be included as "import type ..."
|
||||
import { EventTemplate, UnsignedEvent, VerifiedEvent } from "nostr-tools/core";
|
||||
import { finalizeEvent } from "nostr-tools";
|
||||
import * as nip06 from "nostr-tools/nip06";
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { LMap, LMarker, LTileLayer } from "@vue-leaflet/vue-leaflet";
|
||||
@@ -254,6 +252,7 @@ import {
|
||||
retrieveAccountCount,
|
||||
retrieveFullyDecryptedAccount,
|
||||
} from "../libs/util";
|
||||
import { EventTemplate, UnsignedEvent, VerifiedEvent } from "nostr-tools/core";
|
||||
|
||||
@Component({
|
||||
components: { ImageMethodDialog, LMap, LMarker, LTileLayer, QuickNav },
|
||||
|
||||
Reference in New Issue
Block a user