@@ -15,6 +15,7 @@ import type {
1515 ObjectType ,
1616 PropertyValidators ,
1717 Validator ,
18+ Value ,
1819} from "convex/values" ;
1920import { asObjectValidator , v } from "convex/values" ;
2021import type {
@@ -70,6 +71,10 @@ import { omit, pick } from "../index.js";
7071 * modified function. All returned ctx and args will show up in the type
7172 * signature for the modified function. To remove something from `ctx`, you
7273 * can return it as `undefined`.
74+
75+ * The `input` function can also return an `onSuccess` callback that will be
76+ * called after the function executes successfully. The `onSuccess` callback
77+ * has access to resources created during input processing via closure.
7378 */
7479export type Customization <
7580 Ctx extends Record < string , any > ,
@@ -84,8 +89,16 @@ export type Customization<
8489 args : ObjectType < CustomArgsValidator > ,
8590 extra : ExtraArgs ,
8691 ) =>
87- | Promise < { ctx : CustomCtx ; args : CustomMadeArgs } >
88- | { ctx : CustomCtx ; args : CustomMadeArgs } ;
92+ | Promise < {
93+ ctx : CustomCtx ;
94+ args : CustomMadeArgs ;
95+ onSuccess ?: ( result : Value ) => void | Promise < void > ;
96+ } >
97+ | {
98+ ctx : CustomCtx ;
99+ args : CustomMadeArgs ;
100+ onSuccess ?: ( result : Value ) => void | Promise < void > ;
101+ } ;
89102} ;
90103
91104/**
@@ -185,7 +198,15 @@ export const NoOp = {
185198 * const user = await getUserOrNull(ctx);
186199 * const session = await db.get(sessionId);
187200 * const db = wrapDatabaseReader({ user }, ctx.db, rlsRules);
188- * return { ctx: { db, user, session }, args: {} };
201+ * return {
202+ * ctx: { db, user, session },
203+ * args: {},
204+ * onSuccess: (result) => {
205+ * // Optional callback that runs after the function executes
206+ * // Has access to resources created during input processing
207+ * console.log(`Query for ${user.name} returned:`, result);
208+ * }
209+ * };
189210 * },
190211 * });
191212 *
@@ -265,7 +286,15 @@ export function customQuery<
265286 * const user = await getUserOrNull(ctx);
266287 * const session = await db.get(sessionId);
267288 * const db = wrapDatabaseReader({ user }, ctx.db, rlsRules);
268- * return { ctx: { db, user, session }, args: {} };
289+ * return {
290+ * ctx: { db, user, session },
291+ * args: {},
292+ * onSuccess: (result) => {
293+ * // Optional callback that runs after the function executes
294+ * // Has access to resources created during input processing
295+ * console.log(`User ${user.name} returned:`, result);
296+ * }
297+ * };
269298 * },
270299 * });
271300 *
@@ -347,7 +376,17 @@ export function customMutation<
347376 * throw new Error("Invalid secret key");
348377 * }
349378 * const user = await ctx.runQuery(internal.users.getUser, {});
350- * return { ctx: { user }, args: {} };
379+ * // Create resources that can be used in the onSuccess callback
380+ * const logger = createLogger();
381+ * return {
382+ * ctx: { user },
383+ * args: {},
384+ * onSuccess: (result) => {
385+ * // Optional callback that runs after the function executes
386+ * // Has access to resources created during input processing
387+ * logger.info(`Action for user ${user.name} returned:`, result);
388+ * }
389+ * };
351390 * },
352391 * });
353392 *
@@ -444,7 +483,12 @@ function customFnBuilder(
444483 extra ,
445484 ) ;
446485 const args = omit ( allArgs , Object . keys ( inputArgs ) ) ;
447- return handler ( { ...ctx , ...added . ctx } , { ...args , ...added . args } ) ;
486+ const finalCtx = { ...ctx , ...added . ctx } ;
487+ const result = await handler ( finalCtx , { ...args , ...added . args } ) ;
488+ if ( added . onSuccess ) {
489+ await added . onSuccess ( result ?? null ) ;
490+ }
491+ return result ;
448492 } ,
449493 } ) ;
450494 }
@@ -458,7 +502,12 @@ function customFnBuilder(
458502 returns : fn . returns ,
459503 handler : async ( ctx : any , args : any ) => {
460504 const added = await customInput ( ctx , args , extra ) ;
461- return handler ( { ...ctx , ...added . ctx } , { ...args , ...added . args } ) ;
505+ const finalCtx = { ...ctx , ...added . ctx } ;
506+ const result = await handler ( finalCtx , { ...args , ...added . args } ) ;
507+ if ( added . onSuccess ) {
508+ await added . onSuccess ( result ?? null ) ;
509+ }
510+ return result ;
462511 } ,
463512 } ) ;
464513 } ;
0 commit comments