diff --git a/.changeset/fix-beforecreate-validation.md b/.changeset/fix-beforecreate-validation.md new file mode 100644 index 0000000..4dcc86c --- /dev/null +++ b/.changeset/fix-beforecreate-validation.md @@ -0,0 +1,9 @@ +--- +"better-auth-convex": patch +--- + +Fix beforeCreate hook validation error + +Previously, the `create` mutation's input validator required all schema fields to be present, causing validation errors when `beforeCreate` hooks tried to add required fields like `username`. + +This fix makes all input fields optional during validation, allowing `beforeCreate` hooks to add or modify any required fields. The actual schema validation still occurs when inserting into the database, ensuring data integrity. \ No newline at end of file diff --git a/src/api.ts b/src/api.ts index 4a820a3..2191e58 100644 --- a/src/api.ts +++ b/src/api.ts @@ -68,13 +68,14 @@ export const createHandler = async ( beforeCreateHandle?: string; select?: string[]; onCreateHandle?: string; + skipBeforeHooks?: boolean; }, schema: Schema, betterAuthSchema: any ) => { let data = args.input.data; - if (args.beforeCreateHandle) { + if (!args.skipBeforeHooks && args.beforeCreateHandle) { const transformedData = await ctx.runMutation( args.beforeCreateHandle as FunctionHandle<'mutation'>, { @@ -300,6 +301,7 @@ export const deleteOneHandler = async ( }; beforeDeleteHandle?: string; onDeleteHandle?: string; + skipBeforeHooks?: boolean; }, schema: Schema, betterAuthSchema: any @@ -312,7 +314,7 @@ export const deleteOneHandler = async ( let hookDoc = doc; - if (args.beforeDeleteHandle) { + if (!args.skipBeforeHooks && args.beforeDeleteHandle) { const transformedDoc = await ctx.runMutation( args.beforeDeleteHandle as FunctionHandle<'mutation'>, { @@ -348,6 +350,7 @@ export const deleteManyHandler = async ( paginationOpts: any; beforeDeleteHandle?: string; onDeleteHandle?: string; + skipBeforeHooks?: boolean; }, schema: Schema, betterAuthSchema: any @@ -359,7 +362,7 @@ export const deleteManyHandler = async ( await asyncMap(page, async (doc: any) => { let hookDoc = doc; - if (args.beforeDeleteHandle) { + if (!args.skipBeforeHooks && args.beforeDeleteHandle) { const transformedDoc = await ctx.runMutation( args.beforeDeleteHandle as FunctionHandle<'mutation'>, { @@ -401,12 +404,14 @@ export const createApi = >( args: { beforeCreateHandle: v.optional(v.string()), input: v.union( - ...Object.entries(schema.tables).map(([model, table]) => - v.object({ - data: v.object((table as any).validator.fields), + ...Object.entries(schema.tables).map(([model, table]) => { + const fields = partial((table as any).validator.fields); + + return v.object({ + data: v.object(fields), model: v.literal(model), - }) - ) + }); + }) ), select: v.optional(v.array(v.string())), onCreateHandle: v.optional(v.string()),