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/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/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({ 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 {