From 1feb81774128eece32a1c50d67145c77b824b09f Mon Sep 17 00:00:00 2001 From: coder-soft Date: Mon, 6 Jul 2026 22:54:44 +0500 Subject: [PATCH 1/2] fix: production CORS 401, guarded bindSupabase, prod WISP_SECRET - Add CORS headers to 401 response in /ingest so browser shows real error instead of CORS failure - Guard bindSupabase in try/catch so it doesn't crash when wisp isn't initialized (e.g. VITE_CONVEX_URL not set) - Set WISP_SECRET on production convex deployment precious-crocodile-678 - Deployed backend code to production deployment --- convex/http.ts | 9 ++++++++- src/providers/AuthProvider.tsx | 9 +++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/convex/http.ts b/convex/http.ts index c9285fa..22b5e2f 100644 --- a/convex/http.ts +++ b/convex/http.ts @@ -16,7 +16,14 @@ http.route({ method: "POST", handler: httpAction(async (ctx, request) => { if (!isAuthorized(request)) { - return new Response("Unauthorized", { status: 401 }); + return new Response("Unauthorized", { + status: 401, + headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, x-wisp-token", + }, + }); } const body = await request.json() as { events: unknown[] }; diff --git a/src/providers/AuthProvider.tsx b/src/providers/AuthProvider.tsx index dcbb3ac..62877dc 100644 --- a/src/providers/AuthProvider.tsx +++ b/src/providers/AuthProvider.tsx @@ -10,8 +10,13 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => { const [loading, setLoading] = useState(true); useEffect(() => { - // Bind Supabase auth state to Wisp analytics identity - const unsubscribeWisp = bindSupabase(supabase); + // Bind Supabase auth state to Wisp analytics identity (no-op if wisp not initialized) + let unsubscribeWisp = () => {}; + try { + unsubscribeWisp = bindSupabase(supabase); + } catch { + // wisp not initialized — skip analytics identity binding + } // Set up auth state listener FIRST const { From d93525f86d7d79d6634c2bf3afee6f80d0d6f41b Mon Sep 17 00:00:00 2001 From: coder-soft Date: Mon, 6 Jul 2026 23:06:12 +0500 Subject: [PATCH 2/2] fix: eliminate post-filter in getMachineStats with composite index - Add by_machine_type_time composite index on events (machineId, type, timestamp) - getMachineStats now uses the composite index for both error and pageview queries, removing the .filter() post-scan --- convex/dashboard.ts | 10 ++++++---- convex/schema.ts | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/convex/dashboard.ts b/convex/dashboard.ts index 4ee74d8..1ecb1ac 100644 --- a/convex/dashboard.ts +++ b/convex/dashboard.ts @@ -237,8 +237,9 @@ export const getMachineStats = query({ const errorNames = await ctx.db .query("events") - .withIndex("by_machine_time", (q) => q.eq("machineId", machineId)) - .filter((q) => q.eq(q.field("type"), "error")) + .withIndex("by_machine_type_time", (q) => + q.eq("machineId", machineId).eq("type", "error") + ) .collect(); const topErrors = Array.from( errorNames.reduce((map, e) => map.set(e.name, (map.get(e.name) ?? 0) + 1), new Map()) @@ -249,8 +250,9 @@ export const getMachineStats = query({ const pageviews = await ctx.db .query("events") - .withIndex("by_machine_time", (q) => q.eq("machineId", machineId)) - .filter((q) => q.eq(q.field("type"), "pageview")) + .withIndex("by_machine_type_time", (q) => + q.eq("machineId", machineId).eq("type", "pageview") + ) .collect(); const topPages = Array.from( pageviews.reduce((map, e) => map.set(e.url, (map.get(e.url) ?? 0) + 1), new Map()) diff --git a/convex/schema.ts b/convex/schema.ts index 19d9157..cf38856 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -66,6 +66,7 @@ export default defineSchema({ .index("by_session", ["sessionId"]) .index("by_type_time", ["type", "timestamp"]) .index("by_machine_time", ["machineId", "timestamp"]) + .index("by_machine_type_time", ["machineId", "type", "timestamp"]) .searchIndex("search_name", { searchField: "name", filterFields: ["type"] }), dailyStats: defineTable({