Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions convex/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { createClient, type GenericCtx } from "@convex-dev/better-auth";
import {
AuthFunctions,
createClient,
type GenericCtx,
} from "@convex-dev/better-auth";
import { convex, crossDomain } from "@convex-dev/better-auth/plugins";
import { components } from "./_generated/api";
import { components, internal } from "./_generated/api";
import { DataModel } from "./_generated/dataModel";
import { query } from "./_generated/server";
import { betterAuth } from "better-auth";
Expand All @@ -10,6 +14,8 @@ import authSchema from "./betterAuth/schema";

const siteUrl = process.env.PUBLIC_CONVEX_SITE_URL!; // redirects to the convex deployment, which redirects to the referer. if it works don't touch it

const authFunctions: AuthFunctions = internal.auth;

// The component client has methods needed for integrating Convex with Better Auth,
// as well as helper methods for general use.
export const authComponent = createClient<DataModel, typeof authSchema>(
Expand All @@ -18,6 +24,24 @@ export const authComponent = createClient<DataModel, typeof authSchema>(
local: {
schema: authSchema,
},
authFunctions,
triggers: {
user: {
onDelete: async (ctx, doc) => {
if (!doc?.userId) {
return;
}

const backups = await ctx.db
.query("backups")
.withIndex("by_user", (q) => q.eq("userId", doc.userId as string))
.collect();
for (const backup of backups) {
await ctx.db.delete(backup._id);
}
},
Comment on lines +30 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling and consider logging for the deletion loop.

The deletion loop lacks error handling, which could result in partial cleanup if any deletion fails. Additionally, there's no observability into how many backups were deleted or if any failures occurred.

Apply this diff to add error handling and logging:

 onDelete: async (ctx, doc) => {
   if (!doc?.userId) {
     return;
   }

   const backups = await ctx.db
     .query("backups")
     .withIndex("by_user", (q) => q.eq("userId", doc.userId as string))
     .collect();
+  
+  let deletedCount = 0;
+  let failedCount = 0;
+  
   for (const backup of backups) {
-    await ctx.db.delete(backup._id);
+    try {
+      await ctx.db.delete(backup._id);
+      deletedCount++;
+    } catch (error) {
+      console.error(`Failed to delete backup ${backup._id}:`, error);
+      failedCount++;
+    }
   }
+  
+  console.log(`User ${doc.userId} deleted: ${deletedCount} backups removed, ${failedCount} failed`);
 },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onDelete: async (ctx, doc) => {
if (!doc?.userId) {
return;
}
const backups = await ctx.db
.query("backups")
.withIndex("by_user", (q) => q.eq("userId", doc.userId as string))
.collect();
for (const backup of backups) {
await ctx.db.delete(backup._id);
}
},
onDelete: async (ctx, doc) => {
if (!doc?.userId) {
return;
}
const backups = await ctx.db
.query("backups")
.withIndex("by_user", (q) => q.eq("userId", doc.userId as string))
.collect();
let deletedCount = 0;
let failedCount = 0;
for (const backup of backups) {
try {
await ctx.db.delete(backup._id);
deletedCount++;
} catch (error) {
console.error(`Failed to delete backup ${backup._id}:`, error);
failedCount++;
}
}
console.log(`User ${doc.userId} deleted: ${deletedCount} backups removed, ${failedCount} failed`);
},
🤖 Prompt for AI Agents
In convex/auth.ts around lines 30 to 42, the deletion loop for user backups has
no error handling or logging which can lead to partial cleanup and no
observability; wrap each ctx.db.delete call in a try/catch so one failure
doesn’t stop subsequent deletes, count successful and failed deletions, and log
a summary (and individual errors) after the loop; use the repository’s existing
logger (or console.error if none) and avoid swallowing errors silently —
optionally return or rethrow an aggregated error if the caller must know about
failures.

},
},
},
);

Expand Down Expand Up @@ -111,3 +135,5 @@ export const getCurrentUser = query({
return authComponent.safeGetAuthUser(ctx);
},
});

export const { onCreate, onDelete, onUpdate } = authComponent.triggersApi();